Skip to content

Commit 7ebc71b

Browse files
committed
sd-8
1 parent c815626 commit 7ebc71b

File tree

15 files changed

+550
-87
lines changed

15 files changed

+550
-87
lines changed

SemanticDeveloper/SemanticDeveloper/MainWindow.axaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
<MenuItem Header="Commit…" Click="OnGitCommitClick"/>
3333
<MenuItem Header="New Branch…" Click="OnGitNewBranchClick"/>
3434
<MenuItem Header="Switch Branch…" Click="OnGitSwitchBranchClick"/>
35+
<MenuItem Header="Get Latest" Click="OnGitGetLatestClick"/>
3536
<MenuItem Header="Refresh" Click="OnGitRefreshClick"/>
3637
</MenuFlyout>
3738
</Button.Flyout>

SemanticDeveloper/SemanticDeveloper/MainWindow.axaml.cs

Lines changed: 88 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,8 @@ private async Task SelectWorkspaceAsync()
10951095
LoadTree(selected);
10961096
// do not persist workspace; every session should be fresh
10971097

1098+
_ = CheckCodexVersionAsync();
1099+
10981100
// Git check
10991101
if (!GitHelper.IsGitRepository(selected))
11001102
{
@@ -1131,6 +1133,27 @@ private async Task SelectWorkspaceAsync()
11311133
await RestartCliAsync();
11321134
}
11331135

1136+
private async Task CheckCodexVersionAsync()
1137+
{
1138+
try
1139+
{
1140+
var latest = CodexVersionService.TryReadLatestVersion();
1141+
if (!latest.Ok || string.IsNullOrWhiteSpace(latest.Version)) return;
1142+
1143+
var installed = await CodexVersionService.TryGetInstalledVersionAsync(_cli.Command, CurrentWorkspacePath ?? Directory.GetCurrentDirectory());
1144+
if (!installed.Ok || string.IsNullOrWhiteSpace(installed.Version)) return;
1145+
1146+
if (CodexVersionService.IsNewer(latest.Version, installed.Version))
1147+
{
1148+
AppendCliLog($"System: Codex {latest.Version} is available (installed {installed.Version}). Run 'codex update' to upgrade.");
1149+
}
1150+
}
1151+
catch
1152+
{
1153+
// best-effort; ignore failures
1154+
}
1155+
}
1156+
11341157
private void LoadTree(string rootPath)
11351158
{
11361159
void DoLoad()
@@ -1686,7 +1709,7 @@ private void TryApplySyntaxHighlightingForPath(string? filePath)
16861709
".js" => "source.js",
16871710
".ts" => "source.ts",
16881711
".json" => "source.json",
1689-
".xml" => "text.xml",
1712+
".xml" or ".xaml" or ".axaml" or ".csproj" => "text.xml",
16901713
".yml" or ".yaml" => "source.yaml",
16911714
".py" => "source.python",
16921715
".rb" => "source.ruby",
@@ -1700,7 +1723,7 @@ private void TryApplySyntaxHighlightingForPath(string? filePath)
17001723
".ps1" => "source.powershell",
17011724
".sql" => "source.sql",
17021725
".toml" => "source.toml",
1703-
".ini" => "source.ini",
1726+
".ini" or ".sln" => "source.ini",
17041727
_ => "text.plain"
17051728
};
17061729

@@ -2152,7 +2175,8 @@ void HandleLine(string? line)
21522175
var dlg = new Views.InputDialog { Title = "Enter Verification Code" };
21532176
dlg.Prompt = "Paste the verification code from the browser:";
21542177
dlg.Input = string.Empty;
2155-
var code = await dlg.ShowDialog<string?>(this);
2178+
var result = await dlg.ShowDialog<Views.InputDialogResult?>(this);
2179+
var code = result?.Text;
21562180
if (!string.IsNullOrWhiteSpace(code))
21572181
{
21582182
try { await p.StandardInput.WriteLineAsync(code); } catch { }
@@ -3409,20 +3433,58 @@ private async void OnGitCommitClick(object? sender, Avalonia.Interactivity.Route
34093433
};
34103434
dlg.Prompt = "Commit message:";
34113435
dlg.Input = string.Empty;
3412-
var message = await dlg.ShowDialog<string?>(this);
3413-
if (message is null) return;
3436+
dlg.ShowCreatePullRequestOption = true;
3437+
var result = await dlg.ShowDialog<Views.InputDialogResult?>(this);
3438+
if (result is null) return;
3439+
3440+
var message = result.Text;
34143441
var (ok, output, error) = GitHelper.TryCommitAll(CurrentWorkspacePath, message);
34153442
if (ok)
34163443
{
34173444
AppendCliLog(output ?? "Committed.");
34183445
LoadTree(CurrentWorkspacePath);
3446+
3447+
var (pushOk, pushOutput, pushError) = GitHelper.TryPushCurrentBranch(CurrentWorkspacePath);
3448+
if (pushOk)
3449+
{
3450+
if (!string.IsNullOrWhiteSpace(pushOutput)) AppendCliLog(pushOutput);
3451+
else AppendCliLog("Pushed changes to remote.");
3452+
3453+
if (result.CreatePullRequest)
3454+
{
3455+
TryLaunchCreatePullRequest();
3456+
}
3457+
}
3458+
else
3459+
{
3460+
AppendCliLog("Git push failed: " + (pushError ?? "unknown error"));
3461+
if (result.CreatePullRequest)
3462+
{
3463+
AppendCliLog("System: Skipping pull request shortcut because push did not succeed.");
3464+
}
3465+
}
34193466
}
34203467
else
34213468
{
34223469
AppendCliLog("Git commit failed: " + (error ?? "unknown error"));
34233470
}
34243471
}
34253472

3473+
private void TryLaunchCreatePullRequest()
3474+
{
3475+
if (!HasWorkspace || CurrentWorkspacePath is null) return;
3476+
var (ok, url, error) = GitHelper.TryBuildPullRequestUrl(CurrentWorkspacePath);
3477+
if (ok && !string.IsNullOrWhiteSpace(url))
3478+
{
3479+
AppendCliLog("System: Opening browser to create pull request…");
3480+
TryOpenUrl(url!);
3481+
}
3482+
else
3483+
{
3484+
AppendCliLog("System: Unable to prepare pull request: " + (error ?? "unknown error"));
3485+
}
3486+
}
3487+
34263488
private async void OnGitNewBranchClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
34273489
{
34283490
if (!HasWorkspace || CurrentWorkspacePath is null || !IsGitRepo) return;
@@ -3432,7 +3494,8 @@ private async void OnGitNewBranchClick(object? sender, Avalonia.Interactivity.Ro
34323494
};
34333495
dlg.Prompt = "Branch name:";
34343496
dlg.Input = string.Empty;
3435-
var name = await dlg.ShowDialog<string?>(this);
3497+
var result = await dlg.ShowDialog<Views.InputDialogResult?>(this);
3498+
var name = result?.Text;
34363499
if (name is null) return;
34373500
// Create branch based on default branch (main/master) and fetch origin first
34383501
var (ok, output, error) = GitHelper.TryCreateAndCheckoutBranch(CurrentWorkspacePath, name, baseOnDefaultBranch: true, fetchOriginFirst: true);
@@ -3448,6 +3511,23 @@ private async void OnGitNewBranchClick(object? sender, Avalonia.Interactivity.Ro
34483511
}
34493512
}
34503513

3514+
private async void OnGitGetLatestClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
3515+
{
3516+
if (!HasWorkspace || CurrentWorkspacePath is null || !IsGitRepo) return;
3517+
AppendCliLog("System: Fetching latest changes…");
3518+
var (ok, output, error) = await Task.Run(() => GitHelper.TryFetchAndFastForward(CurrentWorkspacePath));
3519+
if (ok)
3520+
{
3521+
AppendCliLog(output ?? "Already up to date.");
3522+
RefreshGitUi();
3523+
LoadTree(CurrentWorkspacePath);
3524+
}
3525+
else
3526+
{
3527+
AppendCliLog("Git update failed: " + (error ?? "unknown error"));
3528+
}
3529+
}
3530+
34513531
private void OnGitRefreshClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
34523532
{
34533533
RefreshGitUi();
@@ -3461,7 +3541,8 @@ private async void OnGitSwitchBranchClick(object? sender, Avalonia.Interactivity
34613541
var dlg = new Views.InputDialog { Title = "Switch Branch" };
34623542
dlg.Prompt = "Branch name:";
34633543
dlg.Input = CurrentBranch;
3464-
var name = await dlg.ShowDialog<string?>(this);
3544+
var result = await dlg.ShowDialog<Views.InputDialogResult?>(this);
3545+
var name = result?.Text;
34653546
if (string.IsNullOrWhiteSpace(name)) return;
34663547
var (ok, output, error) = GitHelper.TryCheckoutBranch(CurrentWorkspacePath, name);
34673548
if (ok)

SemanticDeveloper/SemanticDeveloper/README.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ The app integrates basic Git operations directly in the header. All actions use
105105
- Stages all changes (`*`) and creates a commit with the provided message.
106106
- Uses your Git config for name/email if available; otherwise falls back to a local signature like `<user>@local`.
107107
- If there are no changes, you’ll get a friendly “No changes to commit.” notice.
108+
- Automatically pushes the current branch to its tracked remote (defaults to `origin`).
109+
- Optional: tick **Create Pull Request** to open your browser to a GitHub compare page after a successful push.
108110
- New Branch…
109111
- Creates and checks out a new branch based on the default branch when available.
110112
- Behavior details:
@@ -113,20 +115,31 @@ The app integrates basic Git operations directly in the header. All actions use
113115
- Example log: `Created and checked out 'feature-x' (based on origin/main).`
114116
- Switch Branch…
115117
- Checks out an existing branch by name (no automatic fetch/merge).
118+
- Get Latest
119+
- Fetches from the tracked remote (defaults to `origin`) and fast-forwards the current branch when possible.
120+
- Requires the branch to track a remote counterpart; otherwise a helpful log message is shown.
121+
- Stops early if a merge or rebase would be required (fast-forward only).
116122
- Rollback Changes…
117123
- Hard‑resets the working directory to `HEAD` and deletes untracked files.
118124
- Prompts for confirmation since this discards local changes.
119125
- Refresh
120126
- Refreshes the branch label and the file tree’s Git status coloring.
121127

128+
Example workflow
129+
1. Switch to an existing base branch (e.g., `main` or `master`).
130+
2. Choose **Git ▾ → Get Latest** to fast-forward your local branch.
131+
3. Use **Git ▾ → New Branch…** with your preferred naming convention (e.g., `feature/login-form`).
132+
4. After making changes, select **Commit…**, enter a message, let the app push the branch for you, and optionally enable **Create Pull Request** to jump straight to GitHub once the push completes.
133+
122134
- Initialize Git…
123135
- When the workspace is not a Git repo, an “Initialize Git…” button appears in the header.
124136
- Initializes a repository in the selected folder, stages files, and attempts an initial commit (best‑effort).
125137
- This is the same capability offered right after selecting a non‑repo folder.
126138

127139
Notes
128-
- Operations are local and safe: no network is used except the optional `fetch` for “New Branch…”.
129-
- Pull/push are not exposed in the UI. If desired, they can be added later.
140+
- Operations are local unless a remote call is required (the optional `fetch` during “New Branch…”, the fast-forward fetch performed by “Get Latest”, and the push that runs after each commit).
141+
- Open your workspace at the root of the Git repository (the folder containing `.git/`) so the app can detect and enable Git features; selecting a subdirectory skips the Git UI.
142+
- Pull support is limited to fast-forwarding via **Get Latest**; pushing is still not exposed in the UI.
130143
- On some Linux distros, libgit2 may require additional native dependencies. If the Git library can’t load, the UI will hide Git actions and log a helpful message.
131144

132145
## Conversation & Protocol Behavior

SemanticDeveloper/SemanticDeveloper/SemanticDeveloper.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,5 @@
4444
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
4545
</Content>
4646
</ItemGroup>
47-
4847
<!-- MCP mux removed; servers are loaded directly by Codex via config flags. -->
4948
</Project>

SemanticDeveloper/SemanticDeveloper/SemanticDeveloper/McpMux/Debug/McpMuxServer.deps.json

Lines changed: 0 additions & 23 deletions
This file was deleted.
Binary file not shown.

SemanticDeveloper/SemanticDeveloper/SemanticDeveloper/McpMux/Debug/McpMuxServer.runtimeconfig.json

Lines changed: 0 additions & 12 deletions
This file was deleted.

SemanticDeveloper/SemanticDeveloper/SemanticDeveloper/McpMux/Release/McpMuxServer.deps.json

Lines changed: 0 additions & 23 deletions
This file was deleted.
Binary file not shown.

SemanticDeveloper/SemanticDeveloper/SemanticDeveloper/McpMux/Release/McpMuxServer.runtimeconfig.json

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)