cvkg-cli 0.1.11

Cyber Viking Kvasir Graph (CVKG) - High-fidelity agentic UI framework
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
//! # CVKG Agentic Development Guidelines (v1.2)
//!
//! All AI agents contributing to this crate MUST follow ALL seven rules:
//!
//! ── Karpathy Guidelines (1–4) ────────────────────────────────────────────
//! 1. THINK FIRST     — State assumptions. Surface ambiguity. Push back on complexity.
//! 2. STAY SIMPLE     — Minimum code. No speculative features. No unasked-for abstractions.
//! 3. BE SURGICAL     — Touch only what's required. Own your orphans. Don't improve neighbors.
//! 4. VERIFY GOALS    — Turn tasks into checkable criteria. Loop until they pass. Never commit broken.
//!
//! ── CVKG Extended Protocols (5–7) ────────────────────────────────────────
//! 5. TRIPLE-PASS     — Read the target, its surrounding context, and its full call graph
//                      at least THREE TIMES before making any edit or revision.
//! 6. COMMENT ALL     — Every major pub fn, unsafe block, and non-trivial algorithm in
//                      every .rs/.ts/.h/.wgsl file MUST have a descriptive doc comment.
//                      Comments describe WHY and WHAT CONTRACT, not HOW mechanically.
//! 7. MONITOR LOOPS   — Check every tool call / command for progress every 30 seconds.
//                      After 3 consecutive identical failures, stop, write BLOCKED.md,
//                      and move to unblocked work. Never silently accept a broken state.
//!
//! Sources:
//   Karpathy: https://github.com/multica-ai/andrej-karpathy-skills
//   CVKG Extended: Section 2 of the CVKG Design Specification

//! CVKG CLI toolchain, dev server, and hot reload orchestrator
//!
//! This crate provides the command-line interface for CVKG including:
//! - `cvkg new` for scaffolding new projects
//! - `cvkg dev` for starting the development server with hot reload
//! - `cvkg build` for building for target platforms
//! - `cvkg serve` for starting the WebKit preview server
//  and other development tools.

use clap::{Parser, Subcommand};
use std::path::PathBuf;

pub mod agent_replay;
pub mod build_pipeline;
pub mod dev_runtime;
pub mod patch_engine;
pub mod runtime_connection;
pub mod scaffold;
pub mod webkit_server;
pub mod ws_server;
pub mod asset_pipeline;

/// CVKG Command Line Interface
#[derive(Parser)]
#[command(name = "cvkg")]
#[command(about = "Cyber Viking GUI X CLI", long_about = None)]
struct Cli {
    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Scaffold a new CVKG application workspace
    New {
        /// Name of the new project
        name: String,
        /// Template to use (optional)
        #[arg(long)]
        template: Option<String>,
        /// Initialize git repository
        #[arg(long)]
        git: bool,
    },
    /// Start development server with hot reload
    Dev {
        /// Target platform (native, wasm, etc.)
        #[arg(long)]
        target: Option<String>,
        /// Port to run the dev server on
        #[arg(long, default_value_t = 3000)]
        port: u16,
        /// Enable the inspector
        #[arg(long)]
        inspector: bool,
    },
    /// Build for a specified target platform
    Build {
        /// Target platform
        #[arg(long)]
        target: String,
        /// Release build
        #[arg(long)]
        release: bool,
        /// Features to enable
        #[arg(long)]
        features: Vec<String>,
    },
    /// Start the WebKit preview server (no rebuild)
    Serve {
        /// Port to run the server on
        #[arg(long, default_value_t = 8080)]
        port: u16,
        /// Open in browser after starting
        #[arg(long)]
        open: bool,
        /// Enable the inspector
        #[arg(long)]
        inspector: bool,
    },
    /// Run type-check + component lint + layout audit
    Check {
        /// Run all checks
        #[arg(long)]
        all: bool,
        /// Target platform
        #[arg(long)]
        target: Option<String>,
    },
    /// Run unit and snapshot tests
    Test {
        /// Run UI tests
        #[arg(long)]
        ui: bool,
        /// Target platform
        #[arg(long)]
        target: Option<String>,
    },
    /// Launch the Inspector against a running dev server
    Inspect {
        /// URL of the dev server
        #[arg(long)]
        url: String,
        /// WebSocket port for inspector
        #[arg(long, default_value_t = 8081)]
        ws_port: u16,
    },
    /// Export static WASM bundle for deployment
    Export {
        /// Base path for assets
        #[arg(long)]
        base_path: String,
        /// Optimize the build
        #[arg(long)]
        optimize: bool,
    },
    /// Add a CVKG-compatible component crate
    Add {
        /// Name of the crate to add
        name: String,
        /// Features to enable
        #[arg(long)]
        features: Vec<String>,
    },
    /// Generate a custom theme from design tokens (JSON)
    Theme {
        /// Input JSON file with design tokens
        #[arg(long)]
        input: PathBuf,
        /// Output RS file for generated theme
        #[arg(long)]
        output: PathBuf,
    },
}

fn main() {
    let cli = Cli::parse();

    match cli.command {
        Commands::New {
            name,
            template,
            git,
        } => {
            use console::style;
            let tmpl = scaffold::Template::from_str(template.as_deref());
            let scaffolder = scaffold::Scaffolder::new(name, tmpl, git);
            if let Err(e) = scaffolder.run() {
                eprintln!("{} Scaffolding failed: {}", style("").red(), e);
                std::process::exit(1);
            }
        }
        Commands::Dev {
            target,
            port,
            inspector,
        } => {
            use console::style;
            let target_str = target.as_deref().unwrap_or("native");
            println!("{} Starting CVKG development engine...", style("🚀").cyan());
            println!("   {} Target: {}", style("").dim(), style(target_str).yellow());
            println!("   {} Port:   {}", style("").dim(), style(port).bold());
            println!("   {} Inspector: {}", style("").dim(), if inspector { style("Enabled").green() } else { style("Disabled").dim() });

            let addr = std::net::SocketAddr::from(([0, 0, 0, 0], port));

            // Start the async tokio runtime to run the dev server
            tokio::runtime::Builder::new_multi_thread()
                .enable_all()
                .build()
                .unwrap()
                .block_on(async {
                    if target_str == "wasm" || target_str == "webkit" {
                        println!("{} WebKit preview mode detected. Starting background preview server...", style("🌐").blue());
                        // In a real production CLI, we'd spawn the webkit-server here as a child process
                    }
                    
                    if let Err(e) = ws_server::start_server(addr).await {
                        eprintln!("{} Failed to start dev server: {}", style("").red(), e);
                    }
                });
        }
        Commands::Build {
            target,
            release,
            features,
        } => {
            if let Err(e) = asset_pipeline::AssetPipeline::run("assets") {
                eprintln!("Asset Pipeline failed: {}", e);
            }
            println!("Building for target: {}", target);
            let artifact = build_pipeline::BuildPipeline::compile_project(
                ".",
                Some(&target),
                release,
                &features,
            );
            println!("Build complete. Root ID: {}", artifact.root_id);
        }
        Commands::Serve {
            port,
            open: _,
            inspector: _,
        } => {
            println!("Starting WebKit preview server on port {}", port);
            let addr = std::net::SocketAddr::from(([0, 0, 0, 0], port));

            tokio::runtime::Builder::new_multi_thread()
                .enable_all()
                .build()
                .unwrap()
                .block_on(async {
                    if let Err(e) = webkit_server::start_server(addr).await {
                        eprintln!("Failed to start preview server: {}", e);
                    }
                });
        }
        Commands::Check { all: _, target: _ } => {
            use console::style;
            println!("{} Running CVKG type-check and layout audit...", style("🔍").blue());
            let status = std::process::Command::new("cargo")
                .arg("check")
                .status()
                .expect("Failed to execute cargo check");

            if status.success() {
                println!("{} Check complete: All systems nominal.", style("").green());
            } else {
                eprintln!("{} Check failed.", style("").red());
                std::process::exit(1);
            }
        }
        Commands::Test { ui: _, target: _ } => {
            use console::style;
            println!("{} Running CVKG unit and snapshot tests...", style("🧪").magenta());
            let status = std::process::Command::new("cargo")
                .arg("test")
                .status()
                .expect("Failed to execute cargo test");

            if status.success() {
                println!("{} Tests complete: Berserker validated.", style("").green());
            } else {
                eprintln!("{} Tests failed.", style("").red());
                std::process::exit(1);
            }
        }
        Commands::Inspect { url: _, ws_port } => {
            println!("🔍 Launching CVKG Telemetry Inspector...");
            tokio::runtime::Builder::new_current_thread()
                .enable_all()
                .build()
                .unwrap()
                .block_on(async {
                    let ws_url = format!("ws://localhost:{}/ws/devtools", ws_port);
                    println!("Connecting to dev server at {}...", ws_url);
                    
                    match tokio_tungstenite::connect_async(&ws_url).await {
                        Ok((mut ws_stream, _)) => {
                            println!("✅ Connected to CVKG DevTools Stream");
                            println!("Waiting for telemetry data...\n");
                            
                            use futures_util::StreamExt;
                            while let Some(msg) = ws_stream.next().await {
                                if let Ok(msg) = msg {
                                    if let Ok(text) = msg.to_text() {
                                        if let Ok(json) = serde_json::from_str::<serde_json::Value>(text) {
                                            if let Some(fps) = json.get("fps") {
                                                print!("{esc}[2K\r", esc = 27 as char);
                                                print!("📊 FPS: {} | VRAM: {} MB | VDOM Diff: {} ms", 
                                                    fps, 
                                                    json.get("vram_mb").unwrap_or(&serde_json::json!(0)),
                                                    json.get("diff_ms").unwrap_or(&serde_json::json!(0))
                                                );
                                                use std::io::Write;
                                                std::io::stdout().flush().unwrap();
                                            } else {
                                                println!("📡 Event: {}", text);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        Err(e) => eprintln!("❌ Failed to connect to telemetry stream: {}", e),
                    }
                });
        }
        Commands::Export {
            base_path: _,
            optimize,
        } => {
            if let Err(e) = asset_pipeline::AssetPipeline::run("assets") {
                eprintln!("Asset Pipeline failed: {}", e);
            }
            
            let dist_dir = std::path::Path::new("dist");
            std::fs::create_dir_all(dist_dir).expect("Failed to create dist directory");

            println!("📦 Bundling CVKG WASM for production...");
            let mut cmd = std::process::Command::new("wasm-pack");
            cmd.arg("build").arg("--target").arg("web").arg("--out-dir").arg("dist/pkg");
            if optimize {
                cmd.arg("--release");
            }
            
            let status = cmd.status().expect("Failed to execute wasm-pack");
            if status.success() {
                // Generate production index.html
                let project_name = std::env::current_dir().unwrap().file_name().unwrap().to_str().unwrap().replace("-", "_");
                let html = format!(r#"<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>CVKG Application</title>
    <style>
        body, html {{ margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background: #0b0b14; }}
        canvas {{ width: 100%; height: 100%; display: block; }}
    </style>
</head>
<body>
    <canvas id="cvkg-canvas"></canvas>
    <script type="module">
        import init from './pkg/{}.js';
        init();
    </script>
</body>
</html>"#, project_name);
                
                std::fs::write(dist_dir.join("index.html"), html).expect("Failed to write index.html");
                
                if std::path::Path::new("assets").exists() {
                    println!("📦 Copying assets to dist/assets...");
                    let _ = std::process::Command::new("cp").arg("-r").arg("assets").arg("dist/").status();
                }

                println!("✅ Production Export Complete! Artifacts located in /dist");
            } else {
                eprintln!("❌ Export failed. Ensure wasm-pack is installed.");
            }
        }
        Commands::Add { name, features } => {
            println!("Adding CVKG component crate: {}", name);
            let mut cmd = std::process::Command::new("cargo");
            cmd.arg("add").arg(&name);
            if !features.is_empty() {
                cmd.arg("--features").arg(features.join(","));
            }
            let status = cmd.status().expect("Failed to execute cargo add");
            if !status.success() {
                eprintln!("Failed to add crate.");
            }
        }
        Commands::Theme { input, output } => {
            println!(
                "Generating theme from {} to {}",
                input.display(),
                output.display()
            );
            let json_str = std::fs::read_to_string(&input).expect("Failed to read theme JSON");
            let tokens: serde_json::Value =
                serde_json::from_str(&json_str).expect("Invalid theme JSON");

            let mut rs_content = String::from("/// Generated CVKG Theme\n");
            rs_content.push_str("pub struct Theme {\n");
            if let Some(obj) = tokens.as_object() {
                for key in obj.keys() {
                    rs_content.push_str(&format!("    pub {}: [f32; 4],\n", key));
                }
            }
            rs_content.push_str("}\n\n");

            rs_content.push_str("pub const CUSTOM_THEME: Theme = Theme {\n");
            if let Some(obj) = tokens.as_object() {
                for (key, val) in obj {
                    if let Some(arr) = val.as_array() {
                        if arr.len() == 4 {
                            let r = arr[0].as_f64().unwrap_or(0.0);
                            let g = arr[1].as_f64().unwrap_or(0.0);
                            let b = arr[2].as_f64().unwrap_or(0.0);
                            let a = arr[3].as_f64().unwrap_or(1.0);
                            rs_content.push_str(&format!(
                                "    {}: [{:.2}, {:.2}, {:.2}, {:.2}],\n",
                                key, r, g, b, a
                            ));
                        }
                    }
                }
            }
            rs_content.push_str("};\n");

            std::fs::write(&output, rs_content).expect("Failed to write theme RS file");
            println!("Theme generation successful.");
        }
    }
}