Skip to content

Commit 69cd093

Browse files
ShadowCode 0.30.1: Antigravity verified live; subscription answers shown once
- ACP adapter: prompts wait until a model switch (session/set_config_option for Antigravity, session/set_model for Cursor) is acknowledged. Found live: Antigravity ended a prompt sent during the switch at once with no output. Verified afterwards against the signed-in server: 11 models, a `date +%Y` task through a ShadowCode approval, and session/load resume. - Runner: vendor turns emit model.stream_end, and the transcript no longer repeats a reply under Result when the final text matches (old sessions too). - Transcript: the model note names the product ("Using Cursor · Auto · Cloud"). - Task summary: finished tasks with no changes and no checks get one quiet line; Review changes appears only when files changed. - live_vendor_turn example: --command approves one harmless command. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 5e2be25 commit 69cd093

16 files changed

Lines changed: 219 additions & 42 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
# Changelog
22

3+
## 0.30.1: Antigravity verified live, cleaner answers
4+
5+
- **Antigravity prompts wait for the model switch.** Checked against the real
6+
server after sign-in: a prompt sent while `session/set_config_option` was
7+
still pending ended at once with no output. Prompts now wait for the switch
8+
(Cursor's `session/set_model` too). A live task ran `date +%Y` through a
9+
ShadowCode approval and answered; a follow-up resumed the same session.
10+
- **Answers from subscriptions appear once.** Vendor turns now send
11+
`model.stream_end`, and the final result no longer repeats a reply with the
12+
same text, including in older conversations.
13+
- **"Using Cursor · Auto · Cloud"** instead of "Using auto · Cloud": the model
14+
note names the product, as the picker does.
15+
- **Quiet summary for answers.** A finished task that changed no files and ran
16+
no checks shows one line ("Finished · 7s · No files were changed.") without
17+
a *Review changes* button, which now appears only when there are changes.
18+
319
## 0.30.0: Antigravity that asks first
420

521
- **Antigravity runs through Google's official ACP agent server** (the

‎Cargo.lock‎

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ default-members = ["native/core"]
44
resolver = "2"
55

66
[workspace.package]
7-
version = "0.30.0"
7+
version = "0.30.1"
88
edition = "2021"
99
rust-version = "1.95"
1010
license = "MIT"

‎README.md‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,15 @@ need Ollama, LM Studio or any other model server.
2626
ShadowCode's own tools can be rewound.
2727

2828
Release history is in [CHANGELOG.md](CHANGELOG.md). What's new in this release:
29-
[0.30.0 release notes](docs/RELEASE_NOTES.md).
29+
[0.30.1 release notes](docs/RELEASE_NOTES.md).
3030

3131
## Install
3232

3333
Releases target x86_64 Linux with glibc 2.39 or newer (Ubuntu 24.04 or later).
3434
Download from [GitHub releases](https://github.com/Shadowfetchapps/ShadowCode/releases/latest):
3535

36-
- `ShadowCode_0.30.0_amd64.AppImage`
37-
- `ShadowCode_0.30.0_amd64.deb`
36+
- `ShadowCode_0.30.1_amd64.AppImage`
37+
- `ShadowCode_0.30.1_amd64.deb`
3838
- `SHA256SUMS`
3939

4040
### AppImage (recommended)
@@ -45,7 +45,7 @@ from a checkout of this repository:
4545
```bash
4646
sha256sum --ignore-missing -c SHA256SUMS
4747
git clone https://github.com/Shadowfetchapps/ShadowCode.git
48-
./ShadowCode/scripts/install-appimage.sh ~/Downloads/ShadowCode_0.30.0_amd64.AppImage
48+
./ShadowCode/scripts/install-appimage.sh ~/Downloads/ShadowCode_0.30.1_amd64.AppImage
4949
```
5050

5151
[`scripts/install-appimage.sh`](scripts/install-appimage.sh):
@@ -65,14 +65,14 @@ git clone https://github.com/Shadowfetchapps/ShadowCode.git
6565
AppImages only after a successful install.
6666

6767
To run the AppImage without installing it:
68-
`./ShadowCode_0.30.0_amd64.AppImage --appimage-extract-and-run`. FUSE is not
68+
`./ShadowCode_0.30.1_amd64.AppImage --appimage-extract-and-run`. FUSE is not
6969
required.
7070

7171
### Debian package
7272

7373
```bash
7474
sha256sum --ignore-missing -c SHA256SUMS
75-
sudo apt install ./ShadowCode_0.30.0_amd64.deb
75+
sudo apt install ./ShadowCode_0.30.1_amd64.deb
7676
```
7777

7878
The deb installs `shadowcode` and the same llama.cpp runtime in

‎docs/RELEASE_NOTES.md‎

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
1-
ShadowCode 0.30.0 makes Antigravity a full citizen: it now asks before it
2-
acts, like Codex, Claude Code, Cursor and Grok. The 0.29 notes follow below.
1+
ShadowCode 0.30.1 fixes what a live Antigravity session and a real
2+
conversation showed. The 0.30.0 notes follow below.
3+
4+
## Fixed in 0.30.1
5+
6+
- **Antigravity works end to end.** Tested live after signing in: it lists
7+
its 11 Gemini models, asks ShadowCode before running a command, answers, and
8+
resumes the conversation. A timing bug that made the first prompt end with
9+
no answer is fixed.
10+
- **Answers appear once.** Replies from Codex, Claude Code, Cursor, Grok and
11+
Antigravity are no longer repeated under *Result*.
12+
- **Clearer notes.** The model note reads "Using Cursor · Auto · Cloud", and a
13+
question that changed nothing ends with one quiet line instead of an empty
14+
report card.
315

416
## New in 0.30.0
517

@@ -132,9 +144,9 @@ runtime that ships with the app.
132144

133145
## Downloads
134146

135-
- `ShadowCode_0.30.0_amd64.AppImage`
136-
- `ShadowCode_0.30.0_amd64.deb`
137-
- `ShadowCode_0.30.0_appimage-runtime-sources.tar.gz`
147+
- `ShadowCode_0.30.1_amd64.AppImage`
148+
- `ShadowCode_0.30.1_amd64.deb`
149+
- `ShadowCode_0.30.1_appimage-runtime-sources.tar.gz`
138150
- `SHA256SUMS`
139151

140152
Builds are for x86_64 Linux with glibc 2.39 or newer (Ubuntu 24.04 or later).

‎native/core/examples/live_vendor_turn.rs‎

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,12 @@ async fn main() -> anyhow::Result<()> {
5757
println!("vendor status: {}", picker["vendors"][&vendor]);
5858
return Ok(());
5959
}
60-
let prompts: &[&str] = if second {
60+
// --command: one harmless shell command, so the runtime must ask for
61+
// permission; the approval is granted through the same API the window uses.
62+
let command = std::env::args().any(|a| a == "--command");
63+
let prompts: &[&str] = if command {
64+
&["Run the shell command `date +%Y` in the project folder and reply with only its output."]
65+
} else if second {
6166
&[
6267
"Reply with exactly the word ALPHA and nothing else. Do not use any tools.",
6368
"What single word did you reply with last time? Reply with just that word. Do not use any tools.",
@@ -79,9 +84,24 @@ async fn main() -> anyhow::Result<()> {
7984
}
8085
let id = job["id"].as_str().unwrap_or_default().to_owned();
8186
session = job["session_id"].as_str().map(str::to_owned);
82-
let done = tokio::time::timeout(Duration::from_secs(240), service.engine.wait(&id))
83-
.await
84-
.map_err(|_| anyhow::anyhow!("turn did not finish in 240 s"))??;
87+
let waiting = service.engine.wait(&id);
88+
tokio::pin!(waiting);
89+
let deadline = tokio::time::sleep(Duration::from_secs(240));
90+
tokio::pin!(deadline);
91+
let done = loop {
92+
tokio::select! {
93+
done = &mut waiting => break done?,
94+
_ = &mut deadline => anyhow::bail!("turn did not finish in 240 s"),
95+
_ = tokio::time::sleep(Duration::from_millis(300)), if command => {
96+
let pending = call(&service, "GET", "/api/approvals", json!({})).await?;
97+
for approval in pending["approvals"].as_array().into_iter().flatten() {
98+
println!("approval asked: kind={} command={} reason={}", approval["kind"], approval["command"], approval["reason"]);
99+
let aid = approval["id"].as_str().unwrap_or_default();
100+
call(&service, "POST", &format!("/api/approvals/{aid}"), json!({"decision": "approve", "session_id": approval["session_id"]})).await?;
101+
}
102+
}
103+
}
104+
};
85105
let done = json!(done);
86106
println!(
87107
"status={} in {:.1}s | answer={:?} | error={:?}",

‎native/core/src/cli_agent/acp.rs‎

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ pub struct AcpAdapter {
6565
tool_names: HashMap<String, String>,
6666
options: Option<LaunchOptions>,
6767
prompt_active: bool,
68+
/// A model switch was sent and not yet answered. Prompts wait for it:
69+
/// Antigravity ends a prompt at once, with no output, when the model
70+
/// changes underneath it.
71+
switching: bool,
6872
}
6973
impl AcpAdapter {
7074
pub fn new(vendor: Vendor) -> Self {
@@ -84,6 +88,7 @@ impl AcpAdapter {
8488
tool_names: HashMap::new(),
8589
options: None,
8690
prompt_active: false,
91+
switching: false,
8792
}
8893
}
8994
fn id(&mut self) -> u64 {
@@ -175,6 +180,7 @@ impl AcpAdapter {
175180
{
176181
let set_id = self.id();
177182
self.set_model_id = Some(set_id);
183+
self.switching = true;
178184
step.send.push(request(
179185
set_id,
180186
"session/set_config_option",
@@ -190,15 +196,18 @@ impl AcpAdapter {
190196
{
191197
let set_id = self.id();
192198
self.set_model_id = Some(set_id);
199+
self.switching = true;
193200
step.send.push(request(
194201
set_id,
195202
"session/set_model",
196203
json!({"sessionId":session,"modelId":options.model}),
197204
));
198205
}
199206
}
200-
if let Some((prompt, images)) = self.pending_prompt.take() {
201-
step.send.extend(self.start_prompt(&prompt, &images)?);
207+
if !self.switching {
208+
if let Some((prompt, images)) = self.pending_prompt.take() {
209+
step.send.extend(self.start_prompt(&prompt, &images)?);
210+
}
202211
}
203212
Ok(step)
204213
}
@@ -231,6 +240,8 @@ impl AcpAdapter {
231240
);
232241
}
233242
if Some(id) == self.set_model_id {
243+
self.switching = false;
244+
self.pending_prompt = None;
234245
return Ok(Step::update(Update::TurnFailed(format!(
235246
"{} does not accept model `{}` ({text}). Pick the model again from the list.",
236247
self.vendor.product_label(),
@@ -313,7 +324,13 @@ impl AcpAdapter {
313324
return self.after_session(&session, &res["modes"]);
314325
}
315326
if Some(id) == self.set_model_id {
316-
return Ok(Step::default());
327+
// The model is in place; now send the queued prompt.
328+
self.switching = false;
329+
let mut step = Step::default();
330+
if let Some((prompt, images)) = self.pending_prompt.take() {
331+
step.send.extend(self.start_prompt(&prompt, &images)?);
332+
}
333+
return Ok(step);
317334
}
318335
if Some(id) == self.prompt_id {
319336
self.prompt_active = false;
@@ -559,7 +576,7 @@ impl CliAdapter for AcpAdapter {
559576
)]
560577
}
561578
fn ready(&self) -> bool {
562-
self.phase == Phase::Session
579+
self.phase == Phase::Session && !self.switching
563580
}
564581
fn prompt(&mut self, text: &str, images: &[PromptImage]) -> Result<Vec<String>> {
565582
if self.ready() {

‎native/core/src/cli_agent/runner.rs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,12 @@ async fn apply_update(
660660
}
661661
Update::TurnCompleted { text, interrupted } => {
662662
flush_text(request, message_id, pending_text)?;
663+
// The streamed reply is complete, so the final result can
664+
// recognise it instead of repeating it.
665+
request.events.emit(
666+
"model.stream_end",
667+
json!({"message_id": message_id, "complete": !interrupted}),
668+
)?;
663669
if let Some(text) = text {
664670
if !text.is_empty() {
665671
collected.push_str(&text);
@@ -677,6 +683,10 @@ async fn apply_update(
677683
}
678684
Update::TurnFailed(error) => {
679685
flush_text(request, message_id, pending_text)?;
686+
request.events.emit(
687+
"model.stream_end",
688+
json!({"message_id": message_id, "complete": false}),
689+
)?;
680690
if super::is_limit_error(&error) {
681691
return Err(limit_reached(request, vendor, error, stdin, adapter).await);
682692
}

‎native/core/tests/cli_agent.rs‎

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -676,9 +676,15 @@ fn cursor_acp_command_and_cancel() {
676676
assert!(send
677677
.iter()
678678
.any(|l| l.contains("\"authenticate\"") && l.contains("cursor_login")));
679-
assert!(send
679+
let set_model_id = send
680680
.iter()
681-
.any(|l| l.contains("session/set_model") && l.contains("gpt-5.5[context=272k")));
681+
.find(|l| l.contains("session/set_model") && l.contains("gpt-5.5[context=272k"))
682+
.and_then(|l| serde_json::from_str::<Value>(l).ok())
683+
.and_then(|v| v["id"].as_u64())
684+
.expect("model is set per session");
685+
// The prompt waits until the model switch is acknowledged.
686+
assert!(send.iter().all(|l| !l.contains("session/prompt")));
687+
let (send, _) = feed(&mut *adapter, &[&rpc_result(set_model_id, json!({}))]);
682688
assert!(send.iter().any(|l| l.contains("session/prompt")));
683689
assert!(updates
684690
.iter()
@@ -753,6 +759,16 @@ fn antigravity_runs_through_googles_acp_server() {
753759
.find(|l| l.contains("session/set_config_option"))
754760
.expect("model is set per session");
755761
assert!(set.contains("\"configId\":\"model\"") && set.contains("gemini-3.8-pro"));
762+
// Antigravity ends a prompt at once if the model changes under it, so
763+
// the prompt waits for the switch to be acknowledged.
764+
assert!(send.iter().all(|l| !l.contains("session/prompt")));
765+
let set_id = serde_json::from_str::<Value>(set).unwrap()["id"]
766+
.as_u64()
767+
.unwrap();
768+
let (send, _) = feed(
769+
&mut *adapter,
770+
&[&rpc_result(set_id, json!({"configOptions":[]}))],
771+
);
756772
let prompt = send.iter().find(|l| l.contains("session/prompt")).unwrap();
757773
assert!(prompt.contains("\"type\":\"image\""));
758774
// Permission requests reach ShadowCode as approvals.

‎packaging/shadow-agent.desktop‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ Keywords=agent;llm;coding;shadowfetch;
1313
StartupNotify=true
1414
StartupWMClass=shadowcode
1515
X-GNOME-UsesNotifications=true
16-
X-ShadowCode-Version=0.30.0
16+
X-ShadowCode-Version=0.30.1

0 commit comments

Comments
 (0)