From b842d5b36c13b22b48b7e2f29db27561fec1fcfc Mon Sep 17 00:00:00 2001 From: Shadowfetch Studio <209457103+ShadowfetchStudio@users.noreply.github.com> Date: Sat, 31 Oct 2026 17:04:11 -0400 Subject: [PATCH] fix: guide write delegation when Git history is unavailable --- CHANGELOG.md | 10 +++ Cargo.lock | 4 +- Cargo.toml | 2 +- README.md | 42 ++++++------ docs/RELEASE_NOTES.md | 13 ++++ docs/WINDOWS_LAPTOP_QUALIFICATION.md | 28 ++++++++ docs/WINDOWS_PORT.md | 22 ++++-- native/core/src/subagents.rs | 67 ++++++++++++++++++- .../com.shadowfetch.shadowcode.appdata.xml | 3 + .../com.shadowfetch.shadowcode.desktop | 2 +- packaging/shadow-agent.desktop | 2 +- release/trust/policy | 2 +- src-tauri/tauri.conf.json | 2 +- ui/package-lock.json | 4 +- ui/package.json | 2 +- 15 files changed, 163 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ef476e8..75dbd603 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 2.3.1: Delegation prerequisites + +- Write-subagent guidance now states that an existing Git commit is required. + A failed prerequisite check directs the parent to its own editing tools or + read-only agents instead of asking it to create Git history just to delegate. +- Check the prerequisite before preparing a worktree. Regression coverage + includes plain folders, repositories without commits, and committed repositories. + Windows AppContainer restrictions remain in force; this does not grant external + programs access to the null device or move shell commands outside the sandbox. + ## 2.3.0: Windows - **Windows.** ShadowCode builds and runs on 64-bit Windows 10 (1809 or diff --git a/Cargo.lock b/Cargo.lock index 5acc0c1d..14dcca78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4512,7 +4512,7 @@ dependencies = [ [[package]] name = "shadowcode-core" -version = "2.3.0" +version = "2.3.1" dependencies = [ "anyhow", "base64 0.22.1", @@ -4575,7 +4575,7 @@ dependencies = [ [[package]] name = "shadowcode-desktop" -version = "2.3.0" +version = "2.3.1" dependencies = [ "anyhow", "gdk", diff --git a/Cargo.toml b/Cargo.toml index 1b65c8b3..6dd82530 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ exclude = ["vendor/glib-0.18.5"] resolver = "2" [workspace.package] -version = "2.3.0" +version = "2.3.1" edition = "2021" rust-version = "1.95" license = "Apache-2.0" diff --git a/README.md b/README.md index 7bcf7a93..b9748cd5 100644 --- a/README.md +++ b/README.md @@ -72,16 +72,16 @@ The code is open source; the Shadowfetch and ShadowCode product identity is cove own terminal, go from commit to pull request, preview the app you're building, dictate with your voice, and follow along from your phone. -ShadowCode **2.2.0** is the current public release for Linux and macOS, -available from [GitHub releases](https://github.com/ShadowfetchStudio/ShadowCode/releases/tag/v2.2.0) +ShadowCode **2.3.0** is the current public release for Windows, Linux and macOS, +available from [GitHub releases](https://github.com/ShadowfetchStudio/ShadowCode/releases/tag/v2.3.0) and [shadowcode.org](https://shadowcode.org/). -**2.3.0 is a release candidate**, adding Windows. Its Windows installers -have passed CI and physical-laptop qualification, but public publication -is still pending. See the [candidate release notes](docs/RELEASE_NOTES.md), +**2.3.1 is a release candidate** improving guidance when write delegation is +requested in a folder without Git history. Its qualification is in progress. +See the [release notes](docs/RELEASE_NOTES.md), [Windows qualification record](docs/WINDOWS_LAPTOP_QUALIFICATION.md), and -[release history](CHANGELOG.md). Download instructions below use published -versions; the Windows section describes the forthcoming release. +[release history](CHANGELOG.md). Download instructions below use the published +2.3.0 packages. ## Install @@ -101,10 +101,10 @@ From 2.2.0 each release also carries Flatpak bundles for both architectures checked with `ShadowCode_VERSION_flatpak.sha256`; see [Flatpak](docs/FLATPAK.md)) and macOS disk images (see [macOS](#macos)). Check [GitHub releases](https://github.com/ShadowfetchStudio/ShadowCode/releases) -for published versions. The 2.2.0 x86_64 packages and checksums are: +for published versions. The 2.3.0 x86_64 packages and checksums are: -- `ShadowCode_2.2.0_amd64.AppImage` -- `ShadowCode_2.2.0_amd64.deb` +- `ShadowCode_2.3.0_amd64.AppImage` +- `ShadowCode_2.3.0_amd64.deb` - `SHA256SUMS`, `RELEASE-MANIFEST.json`, `RELEASE-AUTH` and `RELEASE-AUTH.sig` (download these beside the package; the installer checks the publisher's signature before running anything) @@ -138,11 +138,7 @@ cmake. ### Windows -> **Not released yet.** Windows support is in development for the next -> release (2.3.0). No published release includes a Windows installer yet, so -> the steps below do not work today; they describe the planned installer. - -From 2.3.0, releases are planned to also carry `ShadowCode_VERSION_x64-setup.exe` for +Release 2.3.0 includes `ShadowCode_2.3.0_x64-setup.exe` for 64-bit Windows 10 (version 1809 or later) and 11, with its SHA-256 checksum in `ShadowCode_VERSION_windows.sha256`. It installs for your user only (no administrator rights) and includes llama.cpp for local models (CPU) and the @@ -179,7 +175,7 @@ assets are checksum-only and cannot be installed by this new entry point; use the instructions shipped with that released version for those existing assets. The 0.33.0 release attempt failed before signing and publication. Its tag stays unchanged. Version 0.33.1 was the first signed release; the public trust policy -in `release/trust` now authorizes 0.33.0 through 2.3.0. +in `release/trust` now authorizes 0.33.0 through 2.3.1. For development, use [Build from source](#build-from-source). Obtain an independently authenticated installer bundle as described below, @@ -193,7 +189,7 @@ bundle and bootstrap requirements. From that independently authenticated installer bundle, run: ```bash -bash /path/to/trusted-bundle/scripts/install-appimage.sh /path/to/downloads/ShadowCode_2.2.0_amd64.AppImage +bash /path/to/trusted-bundle/scripts/install-appimage.sh /path/to/downloads/ShadowCode_2.3.0_amd64.AppImage ``` The installer takes the AppImage path (or `--recover`), resolves its own trusted @@ -239,7 +235,7 @@ as `--trust-dir` are not installer options. cannot corrupt it. After obtaining and verifying the intended package, run the AppImage without installing it: -`./ShadowCode_2.2.0_amd64.AppImage --appimage-extract-and-run`. FUSE is not +`./ShadowCode_2.3.0_amd64.AppImage --appimage-extract-and-run`. FUSE is not required. ### Debian package @@ -287,16 +283,16 @@ installed. The repository is published by the release workflow only; nothing in ShadowCode adds or contacts it by itself. To install one release by hand instead, verify the Debian artifact using the independently trusted verifier bundle. -`verified-deb-2.2.0` must not already exist; install the verified snapshot: +`verified-deb-2.3.0` must not already exist; install the verified snapshot: ```bash bash /path/to/trusted-bundle/scripts/verify-native-release.sh \ --bundle-dir /path/to/downloads \ --trust-dir /path/to/trusted-bundle/release/trust \ - --artifact ShadowCode_2.2.0_amd64.deb \ - --stage-dir ./verified-deb-2.2.0 \ - --expect-version 2.2.0 -sudo apt install ./verified-deb-2.2.0/ShadowCode_2.2.0_amd64.deb + --artifact ShadowCode_2.3.0_amd64.deb \ + --stage-dir ./verified-deb-2.3.0 \ + --expect-version 2.3.0 +sudo apt install ./verified-deb-2.3.0/ShadowCode_2.3.0_amd64.deb ``` A `.deb` installed by hand this way gets no updates and none of the APT diff --git a/docs/RELEASE_NOTES.md b/docs/RELEASE_NOTES.md index b0be1358..5168fb4d 100644 --- a/docs/RELEASE_NOTES.md +++ b/docs/RELEASE_NOTES.md @@ -1,3 +1,16 @@ +# ShadowCode 2.3.1 — candidate + +Write-subagent guidance now names its Git-history prerequisite and directs +plain-folder tasks to direct editing or read-only agents. A prerequisite check +runs before worktree preparation, with regression coverage for plain folders, +unborn repositories and committed repositories. + +This candidate is still being qualified. It does not change Windows +AppContainer permissions: external Git commands that open the null device can +still fail inside the sandbox. See the [Windows port notes](WINDOWS_PORT.md) +and [qualification record](WINDOWS_LAPTOP_QUALIFICATION.md). The published +2.3.0 notes follow below. + # ShadowCode 2.3.0 ShadowCode 2.3.0 runs on Windows. The 2.2.0 notes follow below. diff --git a/docs/WINDOWS_LAPTOP_QUALIFICATION.md b/docs/WINDOWS_LAPTOP_QUALIFICATION.md index b4ad3526..98632d07 100644 --- a/docs/WINDOWS_LAPTOP_QUALIFICATION.md +++ b/docs/WINDOWS_LAPTOP_QUALIFICATION.md @@ -251,3 +251,31 @@ source rebuilding, installer recovery, and packaged CLI, terminal, desktop, Markdown and MCP checks. This closes the earlier Alpine packaging failure. PR #11 was merged after all candidate checks passed; tagged release builds and publication remain separate steps. + + +## Published v2.3.0 follow-up + +The public installer from [run 41237210012](https://github.com/ShadowfetchStudio/ShadowCode/actions/runs/41237210012) +was downloaded and verified against the published checksums. Its SHA-256 is +`7d4673a3fc15e6bbec9b0f1110cd358f3cecf6b02b922d074a3b3ca6c2dff11a`; +the installed executable is +`015163355181c3576f03da3c11cf25d5ab56a5931eb6ec94f5b92bb556a8c9fd`. +The official PowerShell installer, clean-PATH startup checks and native editor +checks passed. The BusyBox source archive matches the previously validated +archive exactly. + +The fresh Gemma task started at 20:38:51 UTC and ended after 1,029.63 seconds. +The independent check passed all five original tests, which remained unchanged, +but the agent exited with code 1. **This run did not pass qualification.** It +spent steps repeatedly trying to start write subagents in a folder without a +Git repository, then attempted external Git commands that failed to open the +null device inside AppContainer. It eventually edited the helper file, but +exhausted its task budget rather than completing the requested workflow. +A one-job development compilation began during the latter part of this run; +the elapsed time is not a model performance benchmark. + +This exposed incomplete guidance around an existing prerequisite: write +subagents need a repository with an existing commit; direct edits and read-only +subagents do not. The Windows null-device restriction is already described in +the port notes. Passing editor checks or independent tests alone must not be +reported as a successful end-to-end model run. diff --git a/docs/WINDOWS_PORT.md b/docs/WINDOWS_PORT.md index 1761a659..852eb6e4 100644 --- a/docs/WINDOWS_PORT.md +++ b/docs/WINDOWS_PORT.md @@ -1,13 +1,23 @@ # Windows port -Status: Windows 2.3.0 release candidate, qualified on GitHub Windows runners -and a Windows 11 Home x64 laptop (Ryzen 3 5300U, 32 GB RAM). Compilation, -engine tests, installer startup, native editor operations and a local-model -repair task have passed. Public release publication remains pending; a CI -artifact is not a public release. See -[the laptop qualification record](WINDOWS_LAPTOP_QUALIFICATION.md) for exact +Status: Windows 2.3.0 is published. Installation, clean-PATH startup and native +editor checks passed on a Windows 11 Home x64 laptop (Ryzen 3 5300U, 32 GB RAM). +The latest public-installer model run repaired the test fixture but exited +unsuccessfully after failed delegation attempts; it is not a qualification pass. +Version 2.3.1 is a follow-up candidate with clearer delegation prerequisites. +See [the laptop qualification record](WINDOWS_LAPTOP_QUALIFICATION.md) for exact artifact evidence, failed attempts and remaining limitations. +External programs that open the Windows null device themselves can fail in +AppContainer; external Git commands demonstrated this in the public-installer +run. The patched bundled shell has an inherited null handle, but this does not +make every external program compatible. Use the app's dedicated Git operations +for supported repository actions or run explicit Git setup in the terminal. +Write subagents require an existing repository with a commit; ordinary file +editing and read-only delegation do not. The follow-up does not weaken the +sandbox or grant device access. + + ## Phases 1. **Compile.** The workspace builds on Windows (x86_64, MSVC). Unix-only diff --git a/native/core/src/subagents.rs b/native/core/src/subagents.rs index f8f5e152..13d6f3d1 100644 --- a/native/core/src/subagents.rs +++ b/native/core/src/subagents.rs @@ -193,6 +193,16 @@ fn schema(name: &str, description: &str, properties: Value, required: &[&str]) - "parameters":{"type":"object","properties":properties,"required":required,"additionalProperties":false}}}) } +async fn require_write_history( + workspace: &std::path::Path, + cancel: &CancellationToken, +) -> Result<()> { + compare::git(workspace, &["rev-parse", "--verify", "HEAD^{commit}"], cancel) + .await + .context("Write delegation is unavailable without a readable existing Git commit. Continue with your own file-editing tools or a read-only agent; do not initialize or commit a repository just to delegate")?; + Ok(()) +} + pub fn spawn_schema() -> Value { let s = json!({"type":"string"}); let task = json!({ @@ -200,13 +210,13 @@ pub fn spawn_schema() -> Value { "prompt": {"type":"string","description":"Complete, self-contained task. The subagent does not see this conversation."}, "description": {"type":"string","description":"Short label (3-6 words)"}, "model": s, - "write": {"type":"boolean","description":"Edit files in an isolated worktree (write agents only); the diff comes back to you"}, + "write": {"type":"boolean","description":"Edit in a Git worktree; needs an existing commit. Returns a diff."}, }); let mut properties = task.clone(); properties["tasks"] = json!({"type":"array","maxItems":MAX_BATCH,"description":"Several subagents to run in parallel","items":{"type":"object","properties":task,"required":["prompt"],"additionalProperties":false}}); schema( "spawn_agent", - "Start subagents with their own context for focused work (search, planning, review, isolated edits). Give prompt, or tasks to run several in parallel. Returns each result summary and any diff.", + "Delegate focused work. Write agents need an existing Git commit; otherwise edit directly or use read-only agents. Give prompt or tasks for a batch. Returns summaries and diffs.", properties, &[], ) @@ -242,7 +252,7 @@ impl ToolExtensions { let offered = |name: &str| schemas.iter().any(|s| s["function"]["name"] == name); let mut note = String::new(); if let Some(host) = self.host.as_ref().filter(|_| offered("spawn_agent")) { - note.push_str("\n\nSubagents (spawn_agent): delegate focused, self-contained work so your own context stays small; independent tasks can run in parallel via tasks. A subagent sees only the prompt you give it. Read-only agents cannot change files; write agents edit an isolated worktree and return a diff that you review and apply with apply_agent_changes. Available agents:"); + note.push_str("\n\nSubagents (spawn_agent): delegate focused work; independent tasks can run in parallel via tasks. Children see only your prompt. Write agents require an existing Git commit and return a worktree diff for apply_agent_changes. Without Git history, edit directly or use read-only agents; do not initialize or commit a repository just to delegate. Available agents:"); for agent in host.catalog().agents.iter().take(32) { // The project's roles say which model runs an agent. let runs_on = match host.role_model(agent) { @@ -965,6 +975,7 @@ impl SubagentHost { // Write children start from the parent's current files, in a worktree. let mut checkout = None; let workspace = if write { + require_write_history(&self.parent.workspace, &cancel).await?; let base = compare::snapshot(&self.engine.paths().data, &self.parent.workspace, &cancel) .await @@ -1372,3 +1383,53 @@ mod validate_change_tests { } } } + +#[cfg(test)] +mod write_history_tests { + use super::*; + + #[tokio::test] + async fn write_delegation_requires_history_without_creating_it() { + let root = tempfile::tempdir().unwrap(); + let file = root.path().join("work.txt"); + std::fs::write(&file, "unchanged").unwrap(); + let cancel = CancellationToken::new(); + let error = require_write_history(root.path(), &cancel) + .await + .unwrap_err() + .to_string(); + assert!(error.contains("file-editing tools"), "{error}"); + assert!(!root.path().join(".git").exists()); + compare::git(root.path(), &["init", "--quiet", "--template="], &cancel) + .await + .unwrap(); + assert!(require_write_history(root.path(), &cancel).await.is_err()); + compare::git( + root.path(), + &[ + "-c", + "user.name=Delegation Test", + "-c", + "user.email=test@example.invalid", + "-c", + "commit.gpgsign=false", + "commit", + "--allow-empty", + "-m", + "Fixture", + ], + &cancel, + ) + .await + .unwrap(); + let before = compare::git(root.path(), &["rev-parse", "HEAD"], &cancel) + .await + .unwrap(); + require_write_history(root.path(), &cancel).await.unwrap(); + let after = compare::git(root.path(), &["rev-parse", "HEAD"], &cancel) + .await + .unwrap(); + assert_eq!(before, after); + assert_eq!(std::fs::read_to_string(file).unwrap(), "unchanged"); + } +} diff --git a/packaging/com.shadowfetch.shadowcode.appdata.xml b/packaging/com.shadowfetch.shadowcode.appdata.xml index 6366d74a..4d4e4777 100644 --- a/packaging/com.shadowfetch.shadowcode.appdata.xml +++ b/packaging/com.shadowfetch.shadowcode.appdata.xml @@ -29,6 +29,9 @@ shadowcode + +

Clarify Git-history requirements for write subagents and guide plain-folder tasks toward direct edits or read-only delegation.

+

ShadowCode for Windows: a per-user installer with local models (llama.cpp), terminals, subscription tools and an AppContainer sandbox for agent commands.

diff --git a/packaging/flatpak/com.shadowfetch.shadowcode.desktop b/packaging/flatpak/com.shadowfetch.shadowcode.desktop index fe132b9c..c05dff2d 100644 --- a/packaging/flatpak/com.shadowfetch.shadowcode.desktop +++ b/packaging/flatpak/com.shadowfetch.shadowcode.desktop @@ -11,4 +11,4 @@ Keywords=agent;llm;coding;shadowfetch; StartupNotify=true StartupWMClass=shadowcode X-GNOME-UsesNotifications=true -X-ShadowCode-Version=2.3.0 +X-ShadowCode-Version=2.3.1 diff --git a/packaging/shadow-agent.desktop b/packaging/shadow-agent.desktop index eb715ce9..b0f9aec9 100644 --- a/packaging/shadow-agent.desktop +++ b/packaging/shadow-agent.desktop @@ -13,4 +13,4 @@ Keywords=agent;llm;coding;shadowfetch; StartupNotify=true StartupWMClass=shadowcode X-GNOME-UsesNotifications=true -X-ShadowCode-Version=2.3.0 +X-ShadowCode-Version=2.3.1 diff --git a/release/trust/policy b/release/trust/policy index 19fece1b..25a04010 100644 --- a/release/trust/policy +++ b/release/trust/policy @@ -7,4 +7,4 @@ channel=stable minimum-epoch=1 minimum-version=0.33.0 keys=ed25519-spki-sha256 -key=1 f0c60ff8228314616985712f8918c9798c0ecf72b7271e19343a041c25663b7f 0.33.0 2.3.0 +key=1 f0c60ff8228314616985712f8918c9798c0ecf72b7271e19343a041c25663b7f 0.33.0 2.3.1 diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 816c66d0..e2ea7f84 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "ShadowCode", - "version": "2.3.0", + "version": "2.3.1", "identifier": "com.shadowfetch.shadowcode", "build": { "beforeDevCommand": { diff --git a/ui/package-lock.json b/ui/package-lock.json index ca53ee47..2b8c6e76 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "shadow-agent-ui", - "version": "2.3.0", + "version": "2.3.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "shadow-agent-ui", - "version": "2.3.0", + "version": "2.3.1", "license": "Apache-2.0", "dependencies": { "@codemirror/commands": "6.11.1", diff --git a/ui/package.json b/ui/package.json index 8318bb24..f686beec 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "shadow-agent-ui", - "version": "2.3.0", + "version": "2.3.1", "private": true, "license": "Apache-2.0", "type": "module",