mirror of
https://github.com/openai/codex.git
synced 2026-05-02 12:21:26 +03:00
Better handling skill depdenencies on ENV VAR. (#9017)
An experimental flow for env var skill dependencies. Skills can now declare required env vars in SKILL.md; if missing, the CLI prompts the user to get the value, and Core will store it in memory (eventually to a local persistent store) <img width="790" height="169" alt="image" src="https://github.com/user-attachments/assets/cd928918-9403-43cb-a7e7-b8d59bcccd9a" />
This commit is contained in:
@@ -2854,6 +2854,12 @@ impl Renderable for ChatComposer {
|
||||
}
|
||||
|
||||
fn render(&self, area: Rect, buf: &mut Buffer) {
|
||||
self.render_with_mask(area, buf, None);
|
||||
}
|
||||
}
|
||||
|
||||
impl ChatComposer {
|
||||
pub(crate) fn render_with_mask(&self, area: Rect, buf: &mut Buffer, mask_char: Option<char>) {
|
||||
let [composer_rect, textarea_rect, popup_rect] = self.layout_areas(area);
|
||||
match &self.active_popup {
|
||||
ActivePopup::Command(popup) => {
|
||||
@@ -3018,7 +3024,12 @@ impl Renderable for ChatComposer {
|
||||
}
|
||||
|
||||
let mut state = self.textarea_state.borrow_mut();
|
||||
StatefulWidgetRef::render_ref(&(&self.textarea), textarea_rect, buf, &mut state);
|
||||
if let Some(mask_char) = mask_char {
|
||||
self.textarea
|
||||
.render_ref_masked(textarea_rect, buf, &mut state, mask_char);
|
||||
} else {
|
||||
StatefulWidgetRef::render_ref(&(&self.textarea), textarea_rect, buf, &mut state);
|
||||
}
|
||||
if self.textarea.text().is_empty() {
|
||||
let text = if self.input_enabled {
|
||||
self.placeholder_text.as_str().to_string()
|
||||
|
||||
@@ -1251,6 +1251,7 @@ mod tests {
|
||||
header: header.to_string(),
|
||||
question: "Choose an option.".to_string(),
|
||||
is_other: false,
|
||||
is_secret: false,
|
||||
options: Some(vec![
|
||||
RequestUserInputQuestionOption {
|
||||
label: "Option 1".to_string(),
|
||||
@@ -1274,6 +1275,7 @@ mod tests {
|
||||
header: header.to_string(),
|
||||
question: "Choose an option.".to_string(),
|
||||
is_other: true,
|
||||
is_secret: false,
|
||||
options: Some(vec![
|
||||
RequestUserInputQuestionOption {
|
||||
label: "Option 1".to_string(),
|
||||
@@ -1297,6 +1299,7 @@ mod tests {
|
||||
header: header.to_string(),
|
||||
question: "Choose the next step for this task.".to_string(),
|
||||
is_other: false,
|
||||
is_secret: false,
|
||||
options: Some(vec![
|
||||
RequestUserInputQuestionOption {
|
||||
label: "Discuss a code change".to_string(),
|
||||
@@ -1326,6 +1329,7 @@ mod tests {
|
||||
header: header.to_string(),
|
||||
question: "Share details.".to_string(),
|
||||
is_other: false,
|
||||
is_secret: false,
|
||||
options: None,
|
||||
}
|
||||
}
|
||||
@@ -2385,6 +2389,7 @@ mod tests {
|
||||
header: "Next Step".to_string(),
|
||||
question: "What would you like to do next?".to_string(),
|
||||
is_other: false,
|
||||
is_secret: false,
|
||||
options: Some(vec![
|
||||
RequestUserInputQuestionOption {
|
||||
label: "Discuss a code change (Recommended)".to_string(),
|
||||
@@ -2436,6 +2441,7 @@ mod tests {
|
||||
header: "Next Step".to_string(),
|
||||
question: "What would you like to do next?".to_string(),
|
||||
is_other: false,
|
||||
is_secret: false,
|
||||
options: Some(vec![
|
||||
RequestUserInputQuestionOption {
|
||||
label: "Discuss a code change (Recommended)".to_string(),
|
||||
|
||||
@@ -414,7 +414,14 @@ impl RequestUserInputOverlay {
|
||||
if area.width == 0 || area.height == 0 {
|
||||
return;
|
||||
}
|
||||
self.composer.render(area, buf);
|
||||
let is_secret = self
|
||||
.current_question()
|
||||
.is_some_and(|question| question.is_secret);
|
||||
if is_secret {
|
||||
self.composer.render_with_mask(area, buf, Some('*'));
|
||||
} else {
|
||||
self.composer.render(area, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1146,6 +1146,22 @@ impl StatefulWidgetRef for &TextArea {
|
||||
}
|
||||
|
||||
impl TextArea {
|
||||
pub(crate) fn render_ref_masked(
|
||||
&self,
|
||||
area: Rect,
|
||||
buf: &mut Buffer,
|
||||
state: &mut TextAreaState,
|
||||
mask_char: char,
|
||||
) {
|
||||
let lines = self.wrapped_lines(area.width);
|
||||
let scroll = self.effective_scroll(area.height, &lines, state.scroll);
|
||||
state.scroll = scroll;
|
||||
|
||||
let start = scroll as usize;
|
||||
let end = (scroll + area.height).min(lines.len() as u16) as usize;
|
||||
self.render_lines_masked(area, buf, &lines, start..end, mask_char);
|
||||
}
|
||||
|
||||
fn render_lines(
|
||||
&self,
|
||||
area: Rect,
|
||||
@@ -1175,6 +1191,26 @@ impl TextArea {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_lines_masked(
|
||||
&self,
|
||||
area: Rect,
|
||||
buf: &mut Buffer,
|
||||
lines: &[Range<usize>],
|
||||
range: std::ops::Range<usize>,
|
||||
mask_char: char,
|
||||
) {
|
||||
for (row, idx) in range.enumerate() {
|
||||
let r = &lines[idx];
|
||||
let y = area.y + row as u16;
|
||||
let line_range = r.start..r.end - 1;
|
||||
let masked = self.text[line_range.clone()]
|
||||
.chars()
|
||||
.map(|_| mask_char)
|
||||
.collect::<String>();
|
||||
buf.set_string(area.x, y, &masked, Style::default());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user