Repository navigation
Expand file tree
/
Copy pathproject.go
More file actions
150 lines (142 loc) · 6.64 KB
/
Copy pathproject.go
File metadata and controls
150 lines (142 loc) · 6.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package crux
import "strings"
// ProjectContext holds the host-derived project facts (org, repos, policy
// dir, pause state) a runtime is built with and injects into agent boot
// prompts. It is on the Crux surface so a host such as cmd/crux can build one
// without naming crux/agent.
type ProjectContext struct {
Org string
Repos []string
PrimaryRepoName string
ACMMLevel int
PRsAllowed bool
PolicyDir string
// GHHost is the bare hostname of the source forge when it is NOT public
// github.com (e.g. "github.ibm.com" for a GHE spoke), derived from the
// configured github.api_url. Exported to agents as GH_HOST so the gh CLI
// targets the right host — without it every agent gh call went to
// api.github.com where the project's repos do not exist (root-caused live
// 2026-08-20: the security agent's issue/PR creation failed silently on
// every GHE-hosted hive). Empty ⇒ public github.com, nothing exported.
GHHost string
// AppAuthoredPRs mirrors config github.app_authored_prs: when true, push-
// capable agents get the App installation token as GITHUB_TOKEN so the GitHub
// MCP server authors PRs/commits as the App bot. Default false → no token is
// injected and behavior is unchanged (opt-in per hive).
AppAuthoredPRs bool
// SharedUIDReadToken permits read-only App caches without dedicated UIDs.
// Cross-agent read isolation is unavailable in this explicit opt-in mode.
SharedUIDReadToken bool
// AppBotLogin and AppBotUserID identify the installed GitHub App's bot
// account. When AppAuthoredPRs is on, push-capable agents use this bot's
// noreply address ("<user id>+<login>@users.noreply.github.com") for git
// author/committer email so GitHub links their fixer commits to the App
// while the commit name and sign-off still name the lane. AppBotUserID
// resolves the bot's GitHub USER id (not the App id, which GitHub never
// links) and is called at each launch so a failed lookup (0) only costs
// that launch the linkage; nil means unknown.
AppBotLogin string
AppBotUserID func() int64
// BobSessionPrefix mirrors governor.bob.session_prefix. Empty is
// default-off; bob launch commands remain byte-identical unless it or a
// per-agent bob.session_label is configured.
BobSessionPrefix string
// InferenceDefaultModel returns the model an inference-routed agent on
// backend launches with when its own config names none — the
// default_model of whichever gateway / governor.litellm block supplies its
// endpoint (config.AgentRuntimeGovernorConfig.DefaultInferenceModel). A
// live function off the config pointer so a default saved in the dashboard
// reaches the next launch without a restart. Nil means no fallback: the
// launch omits --model and the backend's own default applies.
InferenceDefaultModel func(backend string) string
// RepoPaused reports whether a repo carries an operator pause (#6203). It is
// a live predicate rather than a snapshot list because ProjectContext is
// built once at boot and a pause is taken mid-run — a repo frozen for a
// release must drop out of the next agent's scope without a hive restart.
// Nil means nothing is paused, which is every hive that does not use the
// feature and every test that constructs a ProjectContext literal.
RepoPaused func(repo string) bool
// AgentRepos returns the repositories one agent serves (#6204), and
// AgentPrimaryRepo the repo its prompts should treat as "the" repo. Both
// are live functions rather than a snapshot map because ProjectContext is
// built once at boot while a scope is edited mid-run — a specialist
// re-scoped in the dashboard must reach the next agent launch without a
// hive restart.
//
// Nil means no scoping: every agent gets Repos and PrimaryRepo, which is
// what every hive did before this field and what every test that builds a
// ProjectContext literal still gets.
AgentRepos func(agent string) []string
AgentPrimaryRepo func(agent string) string
}
func (p ProjectContext) PrimaryRepo() string {
if strings.TrimSpace(p.PrimaryRepoName) != "" {
return strings.TrimPrefix(p.PrimaryRepoName, p.Org+"/")
}
if len(p.Repos) > 0 {
return strings.TrimPrefix(p.Repos[0], p.Org+"/")
}
return ""
}
// ActiveRepos is Repos minus the operator-paused entries: the repos an agent
// should be told to work.
//
// PrimaryRepo deliberately does NOT filter. The primary repo is the hive's
// identity — what $HIVE_REPO names and what an agent's workdir is a checkout
// of — and re-pointing it at a different repository because the operator
// froze the first one would be a far larger surprise than the pause itself.
// A paused primary simply stops appearing in the work scope.
func (p ProjectContext) ActiveRepos() []string {
return p.unpaused(p.Repos)
}
// ReposFor returns the repositories the named agent serves, falling back to the
// hive-wide list when the agent is unscoped or no scope function is wired.
func (p ProjectContext) ReposFor(agent string) []string {
if p.AgentRepos == nil {
return p.Repos
}
if repos := p.AgentRepos(agent); repos != nil {
return repos
}
return p.Repos
}
// ActiveReposFor is ReposFor minus the operator-paused entries: the repos the
// named agent should actually be handed work on.
//
// The two narrowings compose rather than override. A scope says which repos an
// agent is FOR (#6204); a pause says which repos are open for work at all
// (#6203). An agent scoped to a repo the operator has since paused is handed
// nothing for it, and unpausing restores it without touching the scope.
func (p ProjectContext) ActiveReposFor(agent string) []string {
return p.unpaused(p.ReposFor(agent))
}
// unpaused drops the operator-paused entries from repos, preserving order.
func (p ProjectContext) unpaused(repos []string) []string {
if p.RepoPaused == nil {
return repos
}
out := make([]string, 0, len(repos))
for _, r := range repos {
if p.RepoPaused(r) {
continue
}
out = append(out, r)
}
return out
}
// PrimaryRepoFor returns the repo the named agent's prompts should treat as
// "the" repo — what $HIVE_REPO names.
//
// Unlike PrimaryRepo() this is per-agent, and it has to be: the shipped
// templates say `gh issue create --repo "$HIVE_REPO"`, so handing a specialist
// scoped away from the hive primary the hive primary would aim every example it
// has at a repository the proxy then refuses. An unscoped agent is unaffected.
// Like PrimaryRepo it does not filter paused repos — see ActiveRepos.
func (p ProjectContext) PrimaryRepoFor(agent string) string {
if p.AgentPrimaryRepo != nil {
if repo := strings.TrimPrefix(strings.TrimSpace(p.AgentPrimaryRepo(agent)), p.Org+"/"); repo != "" {
return repo
}
}
return p.PrimaryRepo()
}