@yemi33/minions 0.1.1989 → 0.1.1990

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -66,26 +66,65 @@ function isAdoProject(project) {
66
66
  return !!(project && project.repoHost === 'ado');
67
67
  }
68
68
 
69
- // Scope the header to the ADO host so a misconfigured remote pointing at
69
+ // Scope the header to the ADO host(s) so a misconfigured remote pointing at
70
70
  // another host (e.g. github.com on a misclassified project) doesn't leak the
71
71
  // bearer token. Falls back to the unscoped `http.extraHeader` key when we
72
- // can't compute a host (still safe — git only sends extraHeader on HTTP/S
72
+ // can't compute any host (still safe — git only sends extraHeader on HTTP/S
73
73
  // transfers, and the engine only invokes ado-git-auth for ADO projects).
74
- function _resolveScopeUrl(project) {
74
+ //
75
+ // W-mped1zap00069ea5 — ADO has TWO canonical URL forms for the same org:
76
+ // - https://dev.azure.com/<org>/... (modern, default for new clones)
77
+ // - https://<org>.visualstudio.com/... (legacy alias, still active)
78
+ // Git scopes `http.<url>.extraHeader` by URL PREFIX match: a header scoped to
79
+ // `office.visualstudio.com` is silently dropped when the remote is
80
+ // `dev.azure.com/office` (and vice-versa). The bearer token is identical for
81
+ // either form, so we emit the header under BOTH scopes to cover whichever
82
+ // alias the project's git remote happens to use.
83
+ function _resolveScopeUrls(project) {
75
84
  try {
76
- if (!project || !project.adoOrg) return null;
85
+ if (!isAdoProject(project) || !project.adoOrg) return [];
86
+ const scopes = new Set();
87
+
88
+ // Always include the modern dev.azure.com host. Remotes cloned via the
89
+ // current ADO UI use this form regardless of what `prUrlBase` says.
90
+ scopes.add('https://dev.azure.com/');
91
+
92
+ // Derive the visualstudio.com form from adoOrg. Works whether adoOrg is
93
+ // the bare org slug ("office") or already a full host ("office.visualstudio.com").
94
+ const orgName = project.adoOrg.includes('.')
95
+ ? project.adoOrg.split('.')[0]
96
+ : project.adoOrg;
97
+ if (orgName) {
98
+ scopes.add(`https://${orgName}.visualstudio.com/`);
99
+ }
100
+
101
+ // Also honor whatever host `getAdoOrgBase` resolves — covers custom
102
+ // prUrlBase values (e.g. self-hosted Azure DevOps Server) that don't
103
+ // match either canonical alias.
77
104
  const base = shared.getAdoOrgBase(project);
78
- if (typeof base !== 'string' || !base.startsWith('http')) return null;
79
- const m = base.match(/^(https?:\/\/[^/]+)/);
80
- return m ? `${m[1]}/` : null;
105
+ if (typeof base === 'string' && base.startsWith('http')) {
106
+ const m = base.match(/^(https?:\/\/[^/]+)/);
107
+ if (m) scopes.add(`${m[1]}/`);
108
+ }
109
+
110
+ // Stable alphabetical order so tests can assert deterministically.
111
+ return Array.from(scopes).sort();
81
112
  } catch (_e) {
82
- return null;
113
+ return [];
83
114
  }
84
115
  }
85
116
 
86
- function _buildHeaderArgs(token, scopeUrl) {
87
- const key = scopeUrl ? `http.${scopeUrl}.extraHeader` : 'http.extraHeader';
88
- return ['-c', `${key}=Authorization: Bearer ${token}`];
117
+ function _buildHeaderArgs(token, scopeUrls) {
118
+ // Empty/null scopes degenerate unscoped fallback (matches pre-W-mped1zap
119
+ // behavior). Still safe because we only inject this for ADO projects.
120
+ if (!Array.isArray(scopeUrls) || scopeUrls.length === 0) {
121
+ return ['-c', `http.extraHeader=Authorization: Bearer ${token}`];
122
+ }
123
+ const args = [];
124
+ for (const scopeUrl of scopeUrls) {
125
+ args.push('-c', `http.${scopeUrl}.extraHeader=Authorization: Bearer ${token}`);
126
+ }
127
+ return args;
89
128
  }
90
129
 
91
130
  function _acquireToken(opts = {}) {
@@ -98,7 +137,7 @@ function getAdoGitExtraArgs(project, opts = {}) {
98
137
  if (!isAdoProject(project)) return [];
99
138
  const now = Date.now();
100
139
  if (_cached && _cached.expiresAt > now) {
101
- return _buildHeaderArgs(_cached.token, _resolveScopeUrl(project));
140
+ return _buildHeaderArgs(_cached.token, _resolveScopeUrls(project));
102
141
  }
103
142
  if (now < _backoffUntil) return [];
104
143
  try {
@@ -109,7 +148,7 @@ function getAdoGitExtraArgs(project, opts = {}) {
109
148
  return [];
110
149
  }
111
150
  _cached = { token, expiresAt: now + TOKEN_TTL_MS };
112
- return _buildHeaderArgs(token, _resolveScopeUrl(project));
151
+ return _buildHeaderArgs(token, _resolveScopeUrls(project));
113
152
  } catch (e) {
114
153
  _backoffUntil = now + ACQUIRE_BACKOFF_MS;
115
154
  const firstLine = String(e && e.message || e).split('\n')[0];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1989",
3
+ "version": "0.1.1990",
4
4
  "description": "Multi-agent AI dev team that runs from ~/.minions/ — five autonomous agents share a single engine, dashboard, and knowledge base",
5
5
  "bin": {
6
6
  "minions": "bin/minions.js"