**Motivations:** - Keep the Lapce fork changes replayable via patch files in the monorepo. - Expose a minimal Smart IDE cockpit UX (agents, runs, services, connection) inside Lapce. **Root causes:** - N/A **Correctifs:** - ia-dev-gateway: parse YAML frontmatter (name/description) from agent markdown files. **Evolutions:** - Export new Lapce patch files for the Smart IDE panel + connection helpers. - Add documentation for the Smart IDE panel. **Pages affectées:** - N/A
614 lines
22 KiB
Diff
614 lines
22 KiB
Diff
From a14d933b0b2c0016a9257912ee9bbfeea0ebb5ad Mon Sep 17 00:00:00 2001
|
|
From: Nicolas Cantu <nicolas.cantu@pm.me>
|
|
Date: Sun, 5 Apr 2026 23:11:33 +0200
|
|
Subject: [PATCH 1/3] feat: add Smart IDE intents palette and scratch actions
|
|
|
|
- Add Smart IDE settings (orchestrator + ia-dev-gateway URLs/tokens)
|
|
- Add '!'-prefixed palette kind to execute orchestrator intents
|
|
- Add commands to fetch orchestrator timeline and list ia-dev agents into scratch docs
|
|
|
|
diff --git a/lapce-app/src/app.rs b/lapce-app/src/app.rs
|
|
index 0676963..6fcf580 100644
|
|
--- a/lapce-app/src/app.rs
|
|
+++ b/lapce-app/src/app.rs
|
|
@@ -2558,6 +2558,7 @@ fn palette_item(
|
|
)
|
|
}
|
|
PaletteItemContent::Line { .. }
|
|
+ | PaletteItemContent::SmartIdeIntent { .. }
|
|
| PaletteItemContent::Workspace { .. }
|
|
| PaletteItemContent::SshHost { .. }
|
|
| PaletteItemContent::Language { .. }
|
|
diff --git a/lapce-app/src/command.rs b/lapce-app/src/command.rs
|
|
index c0cc3b8..25f9027 100644
|
|
--- a/lapce-app/src/command.rs
|
|
+++ b/lapce-app/src/command.rs
|
|
@@ -402,6 +402,10 @@ pub enum LapceWorkbenchCommand {
|
|
#[strum(serialize = "palette.palette_help_and_file")]
|
|
PaletteHelpAndFile,
|
|
|
|
+ #[strum(message = "Smart IDE: Run Intent")]
|
|
+ #[strum(serialize = "palette.smart_ide_intent")]
|
|
+ PaletteSmartIdeIntent,
|
|
+
|
|
#[strum(message = "Run and Debug Restart Current Running")]
|
|
#[strum(serialize = "palette.run_and_debug_restart")]
|
|
RunAndDebugRestart,
|
|
@@ -410,6 +414,14 @@ pub enum LapceWorkbenchCommand {
|
|
#[strum(serialize = "palette.run_and_debug_stop")]
|
|
RunAndDebugStop,
|
|
|
|
+ #[strum(message = "Smart IDE: Open Timeline")]
|
|
+ #[strum(serialize = "smart_ide.timeline")]
|
|
+ SmartIdeTimeline,
|
|
+
|
|
+ #[strum(message = "Smart IDE: List Agents")]
|
|
+ #[strum(serialize = "smart_ide.agents.list")]
|
|
+ SmartIdeListAgents,
|
|
+
|
|
#[strum(serialize = "source_control.checkout_reference")]
|
|
CheckoutReference,
|
|
|
|
diff --git a/lapce-app/src/lib.rs b/lapce-app/src/lib.rs
|
|
index 43a55ce..ea3c659 100644
|
|
--- a/lapce-app/src/lib.rs
|
|
+++ b/lapce-app/src/lib.rs
|
|
@@ -33,6 +33,7 @@
|
|
pub mod settings;
|
|
pub mod snippet;
|
|
pub mod source_control;
|
|
+pub mod smart_ide;
|
|
pub mod status;
|
|
pub mod terminal;
|
|
pub mod text_area;
|
|
diff --git a/lapce-app/src/main_split.rs b/lapce-app/src/main_split.rs
|
|
index d698754..fae3b48 100644
|
|
--- a/lapce-app/src/main_split.rs
|
|
+++ b/lapce-app/src/main_split.rs
|
|
@@ -2429,6 +2429,46 @@ pub fn open_keymap(&self) {
|
|
self.get_editor_tab_child(EditorTabChildSource::Keymap, false, false);
|
|
}
|
|
|
|
+ pub fn open_named_scratch(&self, name: &str, content: String) -> Rc<Doc> {
|
|
+ let name = name.to_string();
|
|
+ let existing =
|
|
+ self.scratch_docs.with_untracked(|scratch_docs| scratch_docs.get(&name).cloned());
|
|
+
|
|
+ let doc = if let Some(doc) = existing {
|
|
+ doc
|
|
+ } else {
|
|
+ let doc_content = DocContent::Scratch {
|
|
+ id: BufferId::next(),
|
|
+ name: name.clone(),
|
|
+ };
|
|
+ let doc = Rc::new(Doc::new_content(
|
|
+ self.scope,
|
|
+ doc_content,
|
|
+ self.editors,
|
|
+ self.common.clone(),
|
|
+ ));
|
|
+ self.scratch_docs.update(|scratch_docs| {
|
|
+ scratch_docs.insert(name.clone(), doc.clone());
|
|
+ });
|
|
+ doc
|
|
+ };
|
|
+
|
|
+ doc.reload(Rope::from(content), true);
|
|
+ doc.set_syntax(Syntax::init(&PathBuf::from(name.clone())));
|
|
+ doc.trigger_syntax_change(None);
|
|
+
|
|
+ self.get_editor_tab_child(
|
|
+ EditorTabChildSource::Editor {
|
|
+ path: PathBuf::from(name),
|
|
+ doc: doc.clone(),
|
|
+ },
|
|
+ false,
|
|
+ false,
|
|
+ );
|
|
+
|
|
+ doc
|
|
+ }
|
|
+
|
|
pub fn new_file(&self) -> EditorTabChild {
|
|
self.get_editor_tab_child(EditorTabChildSource::NewFileEditor, false, false)
|
|
}
|
|
diff --git a/lapce-app/src/palette.rs b/lapce-app/src/palette.rs
|
|
index fb85013..699dfaa 100644
|
|
--- a/lapce-app/src/palette.rs
|
|
+++ b/lapce-app/src/palette.rs
|
|
@@ -11,7 +11,7 @@
|
|
time::Instant,
|
|
};
|
|
|
|
-use anyhow::Result;
|
|
+use anyhow::{Context, Result};
|
|
use floem::{
|
|
ext_event::{create_ext_action, create_signal_from_channel},
|
|
keyboard::Modifiers,
|
|
@@ -344,6 +344,9 @@ pub fn run(&self, kind: PaletteKind) {
|
|
/// Get the placeholder text to use in the palette input field.
|
|
pub fn placeholder_text(&self) -> &'static str {
|
|
match self.kind.get() {
|
|
+ PaletteKind::SmartIdeIntent => {
|
|
+ "Type an intent (e.g. chat.local, git.clone) or select one below"
|
|
+ }
|
|
PaletteKind::SshHost => {
|
|
"Type [user@]host or select a previously connected workspace below"
|
|
}
|
|
@@ -390,6 +393,9 @@ fn run_inner(&self, kind: PaletteKind) {
|
|
PaletteKind::WorkspaceSymbol => {
|
|
self.get_workspace_symbols();
|
|
}
|
|
+ PaletteKind::SmartIdeIntent => {
|
|
+ self.get_smart_ide_intents();
|
|
+ }
|
|
PaletteKind::SshHost => {
|
|
self.get_ssh_hosts();
|
|
}
|
|
@@ -598,6 +604,93 @@ fn get_commands(&self) {
|
|
self.items.set(items);
|
|
}
|
|
|
|
+ fn get_smart_ide_intents(&self) {
|
|
+ const INTENTS: &[(&str, &str)] = &[
|
|
+ ("chat.local", "Chat (LLM/RAG via orchestrator)"),
|
|
+ ("code.complete", "Code completion (LLM via orchestrator)"),
|
|
+ ("rag.query", "RAG query (AnythingLLM via orchestrator)"),
|
|
+ ("git.clone", "Clone repository (repos-devtools)"),
|
|
+ ("search.regex", "Regex search (agent-regex-search-api)"),
|
|
+ ("extract.entities", "Entity extraction (langextract-api)"),
|
|
+ ("doc.office.upload", "Upload office document (local-office)"),
|
|
+ ("tools.registry", "List available tools (tools-bridge)"),
|
|
+ ("tools.carbonyl.plan", "Open Carbonyl preview plan (tools-bridge)"),
|
|
+ ("tools.pageindex.run", "Run PageIndex (tools-bridge)"),
|
|
+ ("tools.chandra.ocr", "Run OCR (tools-bridge)"),
|
|
+ ("agent.run", "Run an ia_dev agent (ia-dev-gateway)"),
|
|
+ ];
|
|
+
|
|
+ let items = INTENTS
|
|
+ .iter()
|
|
+ .map(|(intent, label)| PaletteItem {
|
|
+ content: PaletteItemContent::SmartIdeIntent {
|
|
+ intent: (*intent).to_string(),
|
|
+ },
|
|
+ filter_text: format!("{intent} — {label}"),
|
|
+ score: 0,
|
|
+ indices: Vec::new(),
|
|
+ })
|
|
+ .collect();
|
|
+
|
|
+ self.items.set(items);
|
|
+ }
|
|
+
|
|
+ fn smart_ide_execute_intent(&self, intent: String) {
|
|
+ let intent = intent.trim().to_string();
|
|
+ if intent.is_empty() {
|
|
+ self.common.internal_command.send(InternalCommand::ShowAlert {
|
|
+ title: "Smart IDE".to_string(),
|
|
+ msg: "Intent is empty.".to_string(),
|
|
+ buttons: Vec::new(),
|
|
+ });
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ let config = self.common.config.get_untracked();
|
|
+ if let Err(err) = crate::smart_ide::orchestrator_token(&config) {
|
|
+ self.common.internal_command.send(InternalCommand::ShowAlert {
|
|
+ title: "Smart IDE".to_string(),
|
|
+ msg: err.to_string(),
|
|
+ buttons: Vec::new(),
|
|
+ });
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ self.main_split.open_named_scratch(
|
|
+ "SmartIDE-output.json",
|
|
+ format!("Running intent: {intent}\n"),
|
|
+ );
|
|
+
|
|
+ let main_split = self.main_split.clone();
|
|
+ let send = create_ext_action(self.common.scope, move |result: Result<String>| {
|
|
+ match result {
|
|
+ Ok(text) => {
|
|
+ main_split.open_named_scratch("SmartIDE-output.json", text);
|
|
+ }
|
|
+ Err(err) => {
|
|
+ main_split.open_named_scratch(
|
|
+ "SmartIDE-output.json",
|
|
+ format!("Error:\n{err}"),
|
|
+ );
|
|
+ }
|
|
+ }
|
|
+ });
|
|
+
|
|
+ let intent_for_thread = intent.clone();
|
|
+ std::thread::Builder::new()
|
|
+ .name("SmartIdeExecuteIntent".to_owned())
|
|
+ .spawn(move || {
|
|
+ let run = || -> Result<String> {
|
|
+ let resp =
|
|
+ crate::smart_ide::orchestrator_execute(&config, &intent_for_thread)?;
|
|
+ serde_json::to_string_pretty(&resp)
|
|
+ .context("Failed to format JSON response")
|
|
+ };
|
|
+ send(run());
|
|
+ })
|
|
+ .ok();
|
|
+ }
|
|
+
|
|
/// Initialize the palette with all the available workspaces, local and remote.
|
|
fn get_workspaces(&self) {
|
|
let db: Arc<LapceDb> = use_context().unwrap();
|
|
@@ -1188,6 +1281,9 @@ fn select(&self) {
|
|
PaletteItemContent::Command { cmd } => {
|
|
self.common.lapce_command.send(cmd.clone());
|
|
}
|
|
+ PaletteItemContent::SmartIdeIntent { intent } => {
|
|
+ self.smart_ide_execute_intent(intent.clone());
|
|
+ }
|
|
PaletteItemContent::Workspace { workspace } => {
|
|
self.common.window_common.window_command.send(
|
|
WindowCommand::SetWorkspace {
|
|
@@ -1342,6 +1438,9 @@ fn select(&self) {
|
|
},
|
|
},
|
|
);
|
|
+ } else if self.kind.get_untracked() == PaletteKind::SmartIdeIntent {
|
|
+ let input = self.input.with_untracked(|input| input.input.clone());
|
|
+ self.smart_ide_execute_intent(input);
|
|
}
|
|
}
|
|
|
|
@@ -1387,6 +1486,7 @@ fn preview(&self) {
|
|
);
|
|
}
|
|
PaletteItemContent::Command { .. } => {}
|
|
+ PaletteItemContent::SmartIdeIntent { .. } => {}
|
|
PaletteItemContent::Workspace { .. } => {}
|
|
PaletteItemContent::RunAndDebug { .. } => {}
|
|
PaletteItemContent::SshHost { .. } => {}
|
|
diff --git a/lapce-app/src/palette/item.rs b/lapce-app/src/palette/item.rs
|
|
index 8f0cf04..f9e7833 100644
|
|
--- a/lapce-app/src/palette/item.rs
|
|
+++ b/lapce-app/src/palette/item.rs
|
|
@@ -24,6 +24,9 @@ pub enum PaletteItemContent {
|
|
PaletteHelp {
|
|
cmd: LapceWorkbenchCommand,
|
|
},
|
|
+ SmartIdeIntent {
|
|
+ intent: String,
|
|
+ },
|
|
File {
|
|
path: PathBuf,
|
|
full_path: PathBuf,
|
|
diff --git a/lapce-app/src/palette/kind.rs b/lapce-app/src/palette/kind.rs
|
|
index 1a1b894..6e9e56f 100644
|
|
--- a/lapce-app/src/palette/kind.rs
|
|
+++ b/lapce-app/src/palette/kind.rs
|
|
@@ -12,6 +12,7 @@ pub enum PaletteKind {
|
|
Reference,
|
|
DocumentSymbol,
|
|
WorkspaceSymbol,
|
|
+ SmartIdeIntent,
|
|
SshHost,
|
|
#[cfg(windows)]
|
|
WslHost,
|
|
@@ -34,6 +35,7 @@ pub fn symbol(&self) -> &'static str {
|
|
PaletteKind::Line => "/",
|
|
PaletteKind::DocumentSymbol => "@",
|
|
PaletteKind::WorkspaceSymbol => "#",
|
|
+ PaletteKind::SmartIdeIntent => "!",
|
|
// PaletteKind::GlobalSearch => "?",
|
|
PaletteKind::Workspace => ">",
|
|
PaletteKind::Command => ":",
|
|
@@ -61,6 +63,7 @@ pub fn from_input(input: &str) -> PaletteKind {
|
|
_ if input.starts_with('/') => PaletteKind::Line,
|
|
_ if input.starts_with('@') => PaletteKind::DocumentSymbol,
|
|
_ if input.starts_with('#') => PaletteKind::WorkspaceSymbol,
|
|
+ _ if input.starts_with('!') => PaletteKind::SmartIdeIntent,
|
|
_ if input.starts_with('>') => PaletteKind::Workspace,
|
|
_ if input.starts_with(':') => PaletteKind::Command,
|
|
_ if input.starts_with('<') => PaletteKind::TerminalProfile,
|
|
@@ -79,6 +82,9 @@ pub fn command(self) -> Option<LapceWorkbenchCommand> {
|
|
PaletteKind::WorkspaceSymbol => {
|
|
Some(LapceWorkbenchCommand::PaletteWorkspaceSymbol)
|
|
}
|
|
+ PaletteKind::SmartIdeIntent => {
|
|
+ Some(LapceWorkbenchCommand::PaletteSmartIdeIntent)
|
|
+ }
|
|
PaletteKind::Workspace => Some(LapceWorkbenchCommand::PaletteWorkspace),
|
|
PaletteKind::Command => Some(LapceWorkbenchCommand::PaletteCommand),
|
|
PaletteKind::File => Some(LapceWorkbenchCommand::Palette),
|
|
@@ -136,6 +142,7 @@ pub fn get_input<'a>(&self, input: &'a str) -> &'a str {
|
|
| PaletteKind::Workspace
|
|
| PaletteKind::DocumentSymbol
|
|
| PaletteKind::WorkspaceSymbol
|
|
+ | PaletteKind::SmartIdeIntent
|
|
| PaletteKind::Line
|
|
| PaletteKind::TerminalProfile
|
|
// | PaletteType::GlobalSearch
|
|
diff --git a/lapce-app/src/smart_ide.rs b/lapce-app/src/smart_ide.rs
|
|
new file mode 100644
|
|
index 0000000..44f6478
|
|
--- /dev/null
|
|
+++ b/lapce-app/src/smart_ide.rs
|
|
@@ -0,0 +1,154 @@
|
|
+use std::time::Duration;
|
|
+
|
|
+use anyhow::{Context, Result, anyhow};
|
|
+use reqwest::blocking::Client;
|
|
+use serde_json::{Value, json};
|
|
+
|
|
+use crate::config::LapceConfig;
|
|
+
|
|
+pub const CONFIG_SECTION: &str = "smart-ide";
|
|
+
|
|
+pub const KEY_ORCHESTRATOR_URL: &str = "orchestrator_url";
|
|
+pub const KEY_ORCHESTRATOR_TOKEN: &str = "orchestrator_token";
|
|
+
|
|
+pub const KEY_IA_DEV_GATEWAY_URL: &str = "ia_dev_gateway_url";
|
|
+pub const KEY_IA_DEV_GATEWAY_TOKEN: &str = "ia_dev_gateway_token";
|
|
+
|
|
+fn plugin_string(config: &LapceConfig, key: &str) -> Option<String> {
|
|
+ config
|
|
+ .plugins
|
|
+ .get(CONFIG_SECTION)
|
|
+ .and_then(|m| m.get(key))
|
|
+ .and_then(|v| v.as_str())
|
|
+ .map(|s| s.to_string())
|
|
+}
|
|
+
|
|
+fn normalize_base_url(raw: &str) -> String {
|
|
+ raw.trim_end_matches('/').to_string()
|
|
+}
|
|
+
|
|
+pub fn orchestrator_base_url(config: &LapceConfig) -> String {
|
|
+ plugin_string(config, KEY_ORCHESTRATOR_URL)
|
|
+ .map(|s| normalize_base_url(&s))
|
|
+ .unwrap_or_else(|| "http://127.0.0.1:37145".to_string())
|
|
+}
|
|
+
|
|
+pub fn orchestrator_token(config: &LapceConfig) -> Result<String> {
|
|
+ plugin_string(config, KEY_ORCHESTRATOR_TOKEN).ok_or_else(|| {
|
|
+ anyhow!(
|
|
+ "Missing setting: [smart-ide].{KEY_ORCHESTRATOR_TOKEN}\n\
|
|
+\n\
|
|
+Add it to your settings file:\n\
|
|
+- global: settings.toml\n\
|
|
+- per-workspace: .lapce/settings.toml\n\
|
|
+\n\
|
|
+Example:\n\
|
|
+[smart-ide]\n\
|
|
+orchestrator_url = \"http://127.0.0.1:37145\"\n\
|
|
+orchestrator_token = \"...\""
|
|
+ )
|
|
+ })
|
|
+}
|
|
+
|
|
+pub fn ia_dev_gateway_base_url(config: &LapceConfig) -> String {
|
|
+ plugin_string(config, KEY_IA_DEV_GATEWAY_URL)
|
|
+ .map(|s| normalize_base_url(&s))
|
|
+ .unwrap_or_else(|| "http://127.0.0.1:37144".to_string())
|
|
+}
|
|
+
|
|
+pub fn ia_dev_gateway_token(config: &LapceConfig) -> Result<String> {
|
|
+ plugin_string(config, KEY_IA_DEV_GATEWAY_TOKEN).ok_or_else(|| {
|
|
+ anyhow!(
|
|
+ "Missing setting: [smart-ide].{KEY_IA_DEV_GATEWAY_TOKEN}\n\
|
|
+\n\
|
|
+Add it to your settings file.\n\
|
|
+\n\
|
|
+Example:\n\
|
|
+[smart-ide]\n\
|
|
+ia_dev_gateway_url = \"http://127.0.0.1:37144\"\n\
|
|
+ia_dev_gateway_token = \"...\""
|
|
+ )
|
|
+ })
|
|
+}
|
|
+
|
|
+fn http_client() -> Result<Client> {
|
|
+ Client::builder()
|
|
+ .timeout(Duration::from_secs(20))
|
|
+ .build()
|
|
+ .context("Failed to build HTTP client")
|
|
+}
|
|
+
|
|
+pub fn orchestrator_execute(config: &LapceConfig, intent: &str) -> Result<Value> {
|
|
+ let base_url = orchestrator_base_url(config);
|
|
+ let token = orchestrator_token(config)?;
|
|
+
|
|
+ let url = format!("{base_url}/v1/execute");
|
|
+ let body = json!({
|
|
+ "intent": intent,
|
|
+ });
|
|
+
|
|
+ let client = http_client()?;
|
|
+ let resp = client
|
|
+ .post(url)
|
|
+ .bearer_auth(token)
|
|
+ .json(&body)
|
|
+ .send()
|
|
+ .context("Orchestrator request failed")?;
|
|
+
|
|
+ let status = resp.status();
|
|
+ let text = resp.text().context("Failed to read orchestrator response body")?;
|
|
+ if !status.is_success() {
|
|
+ return Err(anyhow!(
|
|
+ "Orchestrator error (HTTP {status}):\n{text}"
|
|
+ ));
|
|
+ }
|
|
+
|
|
+ serde_json::from_str(&text).context("Failed to parse orchestrator JSON response")
|
|
+}
|
|
+
|
|
+pub fn orchestrator_timeline(config: &LapceConfig) -> Result<Value> {
|
|
+ let base_url = orchestrator_base_url(config);
|
|
+ let token = orchestrator_token(config)?;
|
|
+
|
|
+ let url = format!("{base_url}/v1/timeline");
|
|
+ let client = http_client()?;
|
|
+ let resp = client
|
|
+ .get(url)
|
|
+ .bearer_auth(token)
|
|
+ .send()
|
|
+ .context("Orchestrator request failed")?;
|
|
+
|
|
+ let status = resp.status();
|
|
+ let text = resp.text().context("Failed to read orchestrator response body")?;
|
|
+ if !status.is_success() {
|
|
+ return Err(anyhow!(
|
|
+ "Orchestrator error (HTTP {status}):\n{text}"
|
|
+ ));
|
|
+ }
|
|
+
|
|
+ serde_json::from_str(&text).context("Failed to parse orchestrator JSON response")
|
|
+}
|
|
+
|
|
+pub fn ia_dev_list_agents(config: &LapceConfig) -> Result<Value> {
|
|
+ let base_url = ia_dev_gateway_base_url(config);
|
|
+ let token = ia_dev_gateway_token(config)?;
|
|
+
|
|
+ let url = format!("{base_url}/v1/agents");
|
|
+ let client = http_client()?;
|
|
+ let resp = client
|
|
+ .get(url)
|
|
+ .bearer_auth(token)
|
|
+ .send()
|
|
+ .context("IA-dev-gateway request failed")?;
|
|
+
|
|
+ let status = resp.status();
|
|
+ let text = resp.text().context("Failed to read ia-dev-gateway response body")?;
|
|
+ if !status.is_success() {
|
|
+ return Err(anyhow!(
|
|
+ "IA-dev-gateway error (HTTP {status}):\n{text}"
|
|
+ ));
|
|
+ }
|
|
+
|
|
+ serde_json::from_str(&text).context("Failed to parse ia-dev-gateway JSON response")
|
|
+}
|
|
+
|
|
diff --git a/lapce-app/src/window_tab.rs b/lapce-app/src/window_tab.rs
|
|
index 41223a9..857a215 100644
|
|
--- a/lapce-app/src/window_tab.rs
|
|
+++ b/lapce-app/src/window_tab.rs
|
|
@@ -713,6 +713,100 @@ pub fn run_lapce_command(&self, cmd: LapceCommand) {
|
|
}
|
|
}
|
|
|
|
+ fn smart_ide_open_timeline(&self) {
|
|
+ let config = self.common.config.get_untracked();
|
|
+ if let Err(err) = crate::smart_ide::orchestrator_token(&config) {
|
|
+ self.common.internal_command.send(InternalCommand::ShowAlert {
|
|
+ title: "Smart IDE".to_string(),
|
|
+ msg: err.to_string(),
|
|
+ buttons: Vec::new(),
|
|
+ });
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ self.main_split.open_named_scratch(
|
|
+ "SmartIDE-timeline.json",
|
|
+ "Loading orchestrator timeline...\n".to_string(),
|
|
+ );
|
|
+
|
|
+ let main_split = self.main_split.clone();
|
|
+ let send = create_ext_action(
|
|
+ self.common.scope,
|
|
+ move |result: std::result::Result<String, String>| match result {
|
|
+ Ok(text) => {
|
|
+ main_split.open_named_scratch("SmartIDE-timeline.json", text);
|
|
+ }
|
|
+ Err(err) => {
|
|
+ main_split.open_named_scratch(
|
|
+ "SmartIDE-timeline.json",
|
|
+ format!("Error:\n{err}"),
|
|
+ );
|
|
+ }
|
|
+ },
|
|
+ );
|
|
+
|
|
+ std::thread::Builder::new()
|
|
+ .name("SmartIdeTimeline".to_owned())
|
|
+ .spawn(move || {
|
|
+ let result = match crate::smart_ide::orchestrator_timeline(&config) {
|
|
+ Ok(v) => match serde_json::to_string_pretty(&v) {
|
|
+ Ok(s) => Ok(s),
|
|
+ Err(e) => Ok(format!("{v}\n\n(pretty print failed: {e})")),
|
|
+ },
|
|
+ Err(e) => Err(e.to_string()),
|
|
+ };
|
|
+ send(result);
|
|
+ })
|
|
+ .ok();
|
|
+ }
|
|
+
|
|
+ fn smart_ide_list_agents(&self) {
|
|
+ let config = self.common.config.get_untracked();
|
|
+ if let Err(err) = crate::smart_ide::ia_dev_gateway_token(&config) {
|
|
+ self.common.internal_command.send(InternalCommand::ShowAlert {
|
|
+ title: "Smart IDE".to_string(),
|
|
+ msg: err.to_string(),
|
|
+ buttons: Vec::new(),
|
|
+ });
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ self.main_split.open_named_scratch(
|
|
+ "SmartIDE-agents.json",
|
|
+ "Loading ia-dev-gateway agents...\n".to_string(),
|
|
+ );
|
|
+
|
|
+ let main_split = self.main_split.clone();
|
|
+ let send = create_ext_action(
|
|
+ self.common.scope,
|
|
+ move |result: std::result::Result<String, String>| match result {
|
|
+ Ok(text) => {
|
|
+ main_split.open_named_scratch("SmartIDE-agents.json", text);
|
|
+ }
|
|
+ Err(err) => {
|
|
+ main_split.open_named_scratch(
|
|
+ "SmartIDE-agents.json",
|
|
+ format!("Error:\n{err}"),
|
|
+ );
|
|
+ }
|
|
+ },
|
|
+ );
|
|
+
|
|
+ std::thread::Builder::new()
|
|
+ .name("SmartIdeListAgents".to_owned())
|
|
+ .spawn(move || {
|
|
+ let result = match crate::smart_ide::ia_dev_list_agents(&config) {
|
|
+ Ok(v) => match serde_json::to_string_pretty(&v) {
|
|
+ Ok(s) => Ok(s),
|
|
+ Err(e) => Ok(format!("{v}\n\n(pretty print failed: {e})")),
|
|
+ },
|
|
+ Err(e) => Err(e.to_string()),
|
|
+ };
|
|
+ send(result);
|
|
+ })
|
|
+ .ok();
|
|
+ }
|
|
+
|
|
pub fn run_workbench_command(
|
|
&self,
|
|
cmd: LapceWorkbenchCommand,
|
|
@@ -1105,6 +1199,7 @@ pub fn run_workbench_command(
|
|
// ==== Palette Commands ====
|
|
PaletteHelp => self.palette.run(PaletteKind::PaletteHelp),
|
|
PaletteHelpAndFile => self.palette.run(PaletteKind::HelpAndFile),
|
|
+ PaletteSmartIdeIntent => self.palette.run(PaletteKind::SmartIdeIntent),
|
|
PaletteLine => {
|
|
self.palette.run(PaletteKind::Line);
|
|
}
|
|
@@ -1141,6 +1236,10 @@ pub fn run_workbench_command(
|
|
}
|
|
DiffFiles => self.palette.run(PaletteKind::DiffFiles),
|
|
|
|
+ // ==== Smart IDE ====
|
|
+ SmartIdeTimeline => self.smart_ide_open_timeline(),
|
|
+ SmartIdeListAgents => self.smart_ide_list_agents(),
|
|
+
|
|
// ==== Running / Debugging ====
|
|
RunAndDebugRestart => {
|
|
let active_term = self.terminal.debug.active_term.get_untracked();
|