Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,25 @@ jobs:
ssh-key: ${{ secrets.DEPLOY_KEY }}
submodules: recursive

# Git dependencies in this repo are public HTTPS. The deploy key is only
# needed when a private git source is configured. webfactory/ssh-agent
# fails the job when ssh-private-key is empty, which skipped every build
# and test on a repo that has no DEPLOY_KEY secret. `secrets` is not a
# valid `if` context, so the presence check is a step output.
- name: Detect deploy key
id: deploy_key
shell: bash
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
run: |
if [ -n "$DEPLOY_KEY" ]; then
echo "present=true" >> "$GITHUB_OUTPUT"
else
echo "present=false" >> "$GITHUB_OUTPUT"
fi

- name: Configure SSH for cargo git dependencies
if: steps.deploy_key.outputs.present == 'true'
uses: webfactory/ssh-agent@dc588b651fe13675774614f8e6a936a468676387
with:
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
Expand Down Expand Up @@ -175,7 +193,25 @@ jobs:
ssh-key: ${{ secrets.DEPLOY_KEY }}
submodules: recursive

# Git dependencies in this repo are public HTTPS. The deploy key is only
# needed when a private git source is configured. webfactory/ssh-agent
# fails the job when ssh-private-key is empty, which skipped every build
# and test on a repo that has no DEPLOY_KEY secret. `secrets` is not a
# valid `if` context, so the presence check is a step output.
- name: Detect deploy key
id: deploy_key
shell: bash
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
run: |
if [ -n "$DEPLOY_KEY" ]; then
echo "present=true" >> "$GITHUB_OUTPUT"
else
echo "present=false" >> "$GITHUB_OUTPUT"
fi

- name: Configure SSH for cargo git dependencies
if: steps.deploy_key.outputs.present == 'true'
uses: webfactory/ssh-agent@dc588b651fe13675774614f8e6a936a468676387
with:
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
Expand Down Expand Up @@ -414,7 +450,25 @@ jobs:
ssh-key: ${{ secrets.DEPLOY_KEY }}
submodules: recursive

# Git dependencies in this repo are public HTTPS. The deploy key is only
# needed when a private git source is configured. webfactory/ssh-agent
# fails the job when ssh-private-key is empty, which skipped every build
# and test on a repo that has no DEPLOY_KEY secret. `secrets` is not a
# valid `if` context, so the presence check is a step output.
- name: Detect deploy key
id: deploy_key
shell: bash
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
run: |
if [ -n "$DEPLOY_KEY" ]; then
echo "present=true" >> "$GITHUB_OUTPUT"
else
echo "present=false" >> "$GITHUB_OUTPUT"
fi

- name: Configure SSH for cargo git dependencies
if: steps.deploy_key.outputs.present == 'true'
uses: webfactory/ssh-agent@dc588b651fe13675774614f8e6a936a468676387
with:
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
Expand Down Expand Up @@ -669,7 +723,25 @@ jobs:
ssh-key: ${{ secrets.DEPLOY_KEY }}
submodules: recursive

# Git dependencies in this repo are public HTTPS. The deploy key is only
# needed when a private git source is configured. webfactory/ssh-agent
# fails the job when ssh-private-key is empty, which skipped every build
# and test on a repo that has no DEPLOY_KEY secret. `secrets` is not a
# valid `if` context, so the presence check is a step output.
- name: Detect deploy key
id: deploy_key
shell: bash
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
run: |
if [ -n "$DEPLOY_KEY" ]; then
echo "present=true" >> "$GITHUB_OUTPUT"
else
echo "present=false" >> "$GITHUB_OUTPUT"
fi

- name: Configure SSH for cargo git dependencies
if: steps.deploy_key.outputs.present == 'true'
uses: webfactory/ssh-agent@dc588b651fe13675774614f8e6a936a468676387
with:
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,23 @@ jobs:
submodules: recursive
fetch-depth: 0

# Same as CI: skip the agent when DEPLOY_KEY is unset. An empty key
# makes webfactory/ssh-agent fail before the release build starts.
# `secrets` is not a valid `if` context, so the presence check is a step output.
- name: Detect deploy key
id: deploy_key
shell: bash
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
run: |
if [ -n "$DEPLOY_KEY" ]; then
echo "present=true" >> "$GITHUB_OUTPUT"
else
echo "present=false" >> "$GITHUB_OUTPUT"
fi

- name: Configure SSH for cargo git dependencies
if: steps.deploy_key.outputs.present == 'true'
uses: webfactory/ssh-agent@dc588b651fe13675774614f8e6a936a468676387
with:
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
Expand Down
22 changes: 22 additions & 0 deletions .github/workflows/require-issue.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,28 @@ jobs:

const owner = context.repo.owner;
const repo = context.repo.repo;

// This repository currently has Issues turned off, and the token
// that runs CI cannot turn them back on. A linked-issue requirement
// then fails every pull request, including Dependabot, with no way
// to open the issue the check demands. Enforce the link only while
// issues exist.
const { data: repoData } = await github.rest.repos.get({ owner, repo });
if (!repoData.has_issues) {
core.info(
'Issues are disabled on this repository, so a linked issue cannot exist. ' +
'The link requirement applies again when issues are enabled.'
);
return;
}

const login = pr.user?.login || '';
// Dependabot cannot open a tracking issue for a lockfile bump.
// Human PRs still have to link a real issue in this repository.
if (login === 'dependabot[bot]') {
core.info('Dependabot pull request; linked issue is not required.');
return;
}
const text = `${pr.title || ''}\n\n${pr.body || ''}`;

// Collect candidate issue numbers that belong to THIS repo.
Expand Down
7 changes: 2 additions & 5 deletions crates/jcode-app-core/src/agent/prompting_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,8 @@ impl Provider for PromptLockProvider {
}

fn unique_temp_dir(tag: &str) -> std::path::PathBuf {
let dir = std::env::temp_dir().join(format!(
"jcode-prompt-lock-{}-{}",
std::process::id(),
tag
));
let dir =
std::env::temp_dir().join(format!("jcode-prompt-lock-{}-{}", std::process::id(), tag));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).expect("create temp prompt dir");
dir
Expand Down
11 changes: 5 additions & 6 deletions crates/jcode-app-core/src/tool/apply_patch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -581,18 +581,17 @@ fn parse_apply_patch(input: &str) -> Result<Vec<PatchHunk>> {
continue;
}

let change_context;
if current == "@@" {
change_context = None;
let change_context = if current == "@@" {
i += 1;
None
} else if let Some(ctx) = current.strip_prefix("@@ ") {
change_context = Some(ctx.to_string());
i += 1;
Some(ctx.to_string())
} else if is_first_chunk {
change_context = None;
None
} else {
break;
}
};

let mut old_lines = Vec::new();
let mut new_lines = Vec::new();
Expand Down
11 changes: 4 additions & 7 deletions crates/jcode-app-core/src/tool/session_search_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,13 +298,10 @@ impl TokenHashIndex {
for (key, mtime_ms, size, overflow, token_count, word_count) in metas {
let bytes = cursor.take(word_count * 8)?;
let bits: Vec<u64> = bytes
.chunks_exact(8)
.map(|chunk| {
u64::from_le_bytes([
chunk[0], chunk[1], chunk[2], chunk[3], chunk[4], chunk[5], chunk[6],
chunk[7],
])
})
.as_chunks::<8>()
.0
.iter()
.map(|chunk| u64::from_le_bytes(*chunk))
.collect();
entries.push(IndexEntry {
key,
Expand Down
4 changes: 3 additions & 1 deletion crates/jcode-base/src/prompt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,9 @@ pub fn append_dynamic_prompt_parts(
if !split.dynamic_part.is_empty() {
split.dynamic_part.push_str("\n\n");
}
split.dynamic_part.push_str(&format!("# Active Skill\n\n{}", skill));
split
.dynamic_part
.push_str(&format!("# Active Skill\n\n{}", skill));
}
}
const SELFDEV_MODE_PROMPT: &str = include_str!("prompt/selfdev_mode.txt");
Expand Down
23 changes: 5 additions & 18 deletions crates/jcode-desktop2/src/scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1311,12 +1311,7 @@ fn draw_transcript(
Affine::scale(scale),
color,
None,
&Rect::new(
x0,
y0,
x1,
y1,
),
&Rect::new(x0, y0, x1, y1),
);
}
if let Some(selection) = model.selection.as_ref()
Expand Down Expand Up @@ -1941,18 +1936,10 @@ mod tests {
for scale in [1.0, 1.25, 1.5, 1.75, 2.0, 2.5] {
let hairline = 1.0 / scale;
let origin = 13.37;
let (_, first_bottom) = diff_band_y(
Rect::new(0.0, 0.0, 100.0, 19.2),
origin,
hairline,
false,
);
let (second_top, _) = diff_band_y(
Rect::new(0.0, 19.2, 100.0, 38.4),
origin,
hairline,
false,
);
let (_, first_bottom) =
diff_band_y(Rect::new(0.0, 0.0, 100.0, 19.2), origin, hairline, false);
let (second_top, _) =
diff_band_y(Rect::new(0.0, 19.2, 100.0, 38.4), origin, hairline, false);
let overlap_px = (first_bottom - second_top) * scale;
assert!(
(overlap_px - 1.0).abs() < 1e-9,
Expand Down
5 changes: 1 addition & 4 deletions crates/jcode-desktop2/src/tests/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1590,10 +1590,7 @@ fn a_new_session_preserves_the_old_panel_until_the_new_one_attaches() {
let (updates_tx, updates_rx) = channel();
let (commands_tx, _commands_rx) = channel();
let commands = crate::harness::CommandSender::for_test(commands_tx);
app.harness = Some((
updates_rx,
commands.clone(),
));
app.harness = Some((updates_rx, commands.clone()));

app.new_session();

Expand Down
10 changes: 3 additions & 7 deletions crates/jcode-tui-markdown/src/markdown_render_full.rs
Original file line number Diff line number Diff line change
Expand Up @@ -640,13 +640,9 @@ pub fn render_markdown_with_width(text: &str, max_width: Option<usize>) -> Vec<L
reasoning_emphasis = true;
}
let is_reasoning = reasoning_emphasis;
let stripped;
let text: &str = if has_sentinel {
stripped = text.replace(crate::REASONING_SENTINEL, "");
&stripped
} else {
&text
};
let stripped =
has_sentinel.then(|| text.replace(crate::REASONING_SENTINEL, ""));
let text: &str = stripped.as_deref().unwrap_or(&*text);
let mut style = if is_thinking_duration || is_reasoning {
Style::default().fg(md_dim_color()).italic()
} else {
Expand Down
10 changes: 3 additions & 7 deletions crates/jcode-tui-markdown/src/markdown_render_lazy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -611,13 +611,9 @@ pub fn render_markdown_lazy(
reasoning_emphasis = true;
}
let is_reasoning = reasoning_emphasis;
let stripped;
let text: &str = if has_sentinel {
stripped = text.replace(crate::REASONING_SENTINEL, "");
&stripped
} else {
&text
};
let stripped =
has_sentinel.then(|| text.replace(crate::REASONING_SENTINEL, ""));
let text: &str = stripped.as_deref().unwrap_or(&*text);
let mut style = if is_thinking_duration || is_reasoning {
Style::default().fg(md_dim_color()).italic()
} else {
Expand Down
9 changes: 4 additions & 5 deletions crates/jcode-tui-render/src/swarm_gallery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -711,8 +711,7 @@ pub fn render_swarm_strip(

let mut spans: Vec<Span<'static>> = lead;
let mut task_used = 0usize;
let used: usize;
if shown == 0 && !chips.is_empty() {
let used: usize = if shown == 0 && !chips.is_empty() {
// Degenerate width: show the first chip truncated.
let budget = width.saturating_sub(lead_w + if show_tally { tail_w + gap } else { 0 });
let c = &chips[0];
Expand All @@ -721,7 +720,7 @@ pub fn render_swarm_strip(
let style = Style::default().fg(c.color);
spans.push(Span::styled(format!("{} ", c.glyph), style));
spans.push(Span::styled(name.clone(), style));
used = disp_w(&c.glyph) + 1 + disp_w(&name);
disp_w(&c.glyph) + 1 + disp_w(&name)
} else {
for (i, chip) in chips.iter().take(shown).enumerate() {
if i > 0 {
Expand Down Expand Up @@ -758,8 +757,8 @@ pub fn render_swarm_strip(
Style::default().fg(rgb(140, 140, 150)),
));
}
used = chips_used + task_used;
}
chips_used + task_used
};

// ---- Right-align the tail (tally [+ hint]) ----
if show_tally {
Expand Down
3 changes: 2 additions & 1 deletion crates/jcode-tui/src/tui/app/turn_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ impl App {
Some(lock)
if lock.skills_fingerprint == fingerprint
&& lock.is_canary == is_canary
&& lock.config_generation == config_generation => {
&& lock.config_generation == config_generation =>
{
(lock.static_part.clone(), lock.context_info.clone())
}
_ => {
Expand Down
Loading
Loading