Forge
csharpdeeb25a2
1using CascadeIDE.Models;
2using CascadeIDE.Services.Intercom;
3
4namespace CascadeIDE.Features.Intercom.Transport;
5
6/// <summary>Resolve team_id: hint → API → manifest strangler (ADR 0144 §2.3.1).</summary>
7public static class IntercomWorkspaceContextResolver
8{
9 public static async Task<IntercomWorkspaceResolveResult> ResolveAsync(
10 IntercomTransportSettings transport,
11 string? workspaceRoot,
12 string? bearerToken,
13 IntercomTransportApiClient api,
14 CancellationToken ct)
15 {
16 var repoKey = IntercomWorkspaceGitRemoteResolver.TryGetNormalizedOrigin(workspaceRoot);
17 if (string.IsNullOrWhiteSpace(transport.TeamId))
18 {
19 if (!string.IsNullOrWhiteSpace(repoKey)
20 && transport.WorkspaceHints.TryGetValue(repoKey, out var hint)
21 && !string.IsNullOrWhiteSpace(hint.TeamId))
22 {
23 return IntercomWorkspaceResolveResult.FromHint(hint.TeamId, repoKey, hint.Source);
24 }
25 }
26
27 if (!string.IsNullOrWhiteSpace(bearerToken) && !string.IsNullOrWhiteSpace(repoKey))
28 {
29 var ctx = await api.ResolveWorkspaceContextAsync(repoKey, bearerToken, ct).ConfigureAwait(false);
30 if (ctx is not null)
31 {
32 var teamId = !string.IsNullOrWhiteSpace(transport.TeamId)
33 ? transport.TeamId.Trim()
34 : ctx.SuggestedTeamId ?? ctx.Teams.FirstOrDefault()?.TeamId ?? "";
35
36 if (!string.IsNullOrWhiteSpace(teamId))
37 {
38 transport.WorkspaceHints[repoKey] = new IntercomWorkspaceHintEntry
39 {
40 TeamId = teamId,
41 ProjectId = ctx.Teams.FirstOrDefault(x => x.TeamId == teamId)?.ProjectId ?? "",
42 UpdatedAtUtc = DateTimeOffset.UtcNow.ToString("O"),
43 Source = "resolve",
44 };
45 return IntercomWorkspaceResolveResult.FromResolve(teamId, repoKey);
46 }
47 }
48 }
49
50 if (string.IsNullOrWhiteSpace(transport.TeamId))
51 {
52 var manifest = IntercomTeamManifestResolver.TryResolve(workspaceRoot);
53 if (manifest is not null && !string.IsNullOrWhiteSpace(manifest.TeamId))
54 {
55 if (!string.IsNullOrWhiteSpace(repoKey))
56 {
57 transport.WorkspaceHints[repoKey] = new IntercomWorkspaceHintEntry
58 {
59 TeamId = manifest.TeamId,
60 UpdatedAtUtc = DateTimeOffset.UtcNow.ToString("O"),
61 Source = "manifest_strangler",
62 };
63 }
64
65 return IntercomWorkspaceResolveResult.FromManifest(manifest.TeamId, repoKey);
66 }
67 }
68
69 var explicitTeam = transport.TeamId.Trim();
70 if (!string.IsNullOrWhiteSpace(explicitTeam))
71 return IntercomWorkspaceResolveResult.FromSettings(explicitTeam, repoKey);
72
73 return IntercomWorkspaceResolveResult.NotFound(repoKey);
74 }
75
76 public static void InvalidateStaleHints(IntercomTransportSettings transport, IntercomMeResponseDto me)
77 {
78 var valid = me.Teams.Select(x => x.TeamId).ToHashSet(StringComparer.Ordinal);
79 var stale = transport.WorkspaceHints
80 .Where(kv => !valid.Contains(kv.Value.TeamId))
81 .Select(kv => kv.Key)
82 .ToList();
83 foreach (var key in stale)
84 transport.WorkspaceHints.Remove(key);
85 }
86}
87
88public sealed record IntercomWorkspaceResolveResult(
89 bool Found,
90 string TeamId,
91 string? RepoKey,
92 string Source)
93{
94 public static IntercomWorkspaceResolveResult FromHint(string teamId, string? repoKey, string source) =>
95 new(true, teamId, repoKey, source);
96
97 public static IntercomWorkspaceResolveResult FromResolve(string teamId, string repoKey) =>
98 new(true, teamId, repoKey, "resolve");
99
100 public static IntercomWorkspaceResolveResult FromManifest(string teamId, string? repoKey) =>
101 new(true, teamId, repoKey, "manifest_strangler");
102
103 public static IntercomWorkspaceResolveResult FromSettings(string teamId, string? repoKey) =>
104 new(true, teamId, repoKey, "settings");
105
106 public static IntercomWorkspaceResolveResult NotFound(string? repoKey) =>
107 new(false, "", repoKey, "");
108}
109
View only · write via MCP/CIDE