Skip to content

Commit 988e4c2

Browse files
committed
fix(providers): replace dead 'netclaw provider fix' references in Copilot
The 'provider fix' subcommand was referenced in three Copilot error messages and the OpenSpec but was never implemented in ProviderCommand.cs. Users hitting an expired OAuth token would have been directed to a command that doesn't exist. Rewrite all sites to the working 'provider remove' + 'provider add' workflow that's already implemented. Updates the matching unit test assertion. Out of scope: the same dead reference exists in OpenAI Codex paths (OpenAiProviderPlugin, OpenAiDescriptor). Tracking separately.
1 parent ce54875 commit 988e4c2

5 files changed

Lines changed: 15 additions & 9 deletions

File tree

openspec/changes/add-github-copilot-provider/specs/netclaw-model-providers/spec.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ credential on the operator's behalf.
105105
- **AND** the endpoint returns `401 Unauthorized`
106106
- **THEN** the system SHALL raise an authentication-expired error
107107
identifying the provider entry by name
108-
- **AND** the remediation message SHALL direct the operator to run
109-
`netclaw provider fix <name>` (or equivalent) to re-run the device flow
108+
- **AND** the remediation message SHALL direct the operator to remove
109+
the entry (`netclaw provider remove <name>`) and re-run the device
110+
flow (`netclaw provider add <name> github-copilot --auth oauth-device`)
110111
- **AND** the stored OAuth token SHALL remain in the secrets store
111112
unchanged so the operator retains visibility into the failing credential

src/Netclaw.Daemon.Tests/Providers/GitHubCopilot/GitHubCopilotDescriptorTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ public async Task Probe_AuthExpired_ReturnsFailWithReauthGuidance()
142142

143143
Assert.False(result.Success);
144144
Assert.Contains("expired", result.ErrorMessage, StringComparison.OrdinalIgnoreCase);
145-
Assert.Contains("provider fix", result.ErrorMessage);
145+
Assert.Contains("provider remove", result.ErrorMessage);
146+
Assert.Contains("provider add", result.ErrorMessage);
146147
Assert.Empty(result.Models);
147148
}
148149

src/Netclaw.Providers/GitHubCopilot/CopilotAuthExpiredException.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@ namespace Netclaw.Providers.GitHubCopilot;
99
/// Thrown when the GitHub OAuth token presented to
1010
/// <c>/copilot_internal/v2/token</c> is rejected with HTTP 401.
1111
/// The stored OAuth token is left intact — the operator must explicitly
12-
/// re-run the device flow via <c>netclaw provider fix &lt;name&gt;</c>.
12+
/// re-run the device flow by removing and re-adding the provider entry
13+
/// (<c>netclaw provider remove &lt;name&gt;</c> followed by
14+
/// <c>netclaw provider add &lt;name&gt; github-copilot --auth oauth-device</c>).
1315
/// </summary>
1416
public sealed class CopilotAuthExpiredException : Exception
1517
{
1618
public CopilotAuthExpiredException()
17-
: base("GitHub Copilot authorization expired. Run 'netclaw provider fix <name>' to re-authenticate.")
19+
: base("GitHub Copilot authorization expired. Run 'netclaw provider remove <name>' "
20+
+ "then 'netclaw provider add <name> github-copilot --auth oauth-device' to re-authenticate.")
1821
{
1922
}
2023
}

src/Netclaw.Providers/GitHubCopilot/CopilotTokenExchanger.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public async Task<string> GetTokenAsync(
5151
ProviderEntry entry, CancellationToken ct = default)
5252
{
5353
var oauthToken = entry.OAuthAccessToken.RequireValid(
54-
"GitHub OAuth access token (run 'netclaw provider fix <name>')");
54+
"GitHub OAuth access token (re-run 'netclaw provider add <name> github-copilot --auth oauth-device')");
5555

5656
var cacheKey = HashKey(oauthToken.Value);
5757
var now = time.GetUtcNow();

src/Netclaw.Providers/GitHubCopilot/GitHubCopilotDescriptor.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public async Task<ProviderProbeResult> ProbeAsync(
5555
{
5656
return new ProviderProbeResult(false,
5757
"GitHub OAuth token is required. Run "
58-
+ "'netclaw provider add <name> --type github-copilot' to authenticate.",
58+
+ "'netclaw provider add <name> github-copilot --auth oauth-device' to authenticate.",
5959
[]);
6060
}
6161

@@ -67,8 +67,9 @@ public async Task<ProviderProbeResult> ProbeAsync(
6767
catch (CopilotAuthExpiredException)
6868
{
6969
return new ProviderProbeResult(false,
70-
"GitHub Copilot authorization expired. Re-authenticate with "
71-
+ "'netclaw provider fix <name>'.",
70+
"GitHub Copilot authorization expired. Re-authenticate by running "
71+
+ "'netclaw provider remove <name>' then "
72+
+ "'netclaw provider add <name> github-copilot --auth oauth-device'.",
7273
[]);
7374
}
7475
catch (HttpRequestException ex)

0 commit comments

Comments
 (0)