@mmnto/cli 1.103.0 → 1.104.0

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.
Files changed (40) hide show
  1. package/dist/commands/doctor-parity-fetch.d.ts +84 -0
  2. package/dist/commands/doctor-parity-fetch.d.ts.map +1 -0
  3. package/dist/commands/doctor-parity-fetch.js +367 -0
  4. package/dist/commands/doctor-parity-fetch.js.map +1 -0
  5. package/dist/commands/doctor-parity-fetch.test.d.ts +13 -0
  6. package/dist/commands/doctor-parity-fetch.test.d.ts.map +1 -0
  7. package/dist/commands/doctor-parity-fetch.test.js +269 -0
  8. package/dist/commands/doctor-parity-fetch.test.js.map +1 -0
  9. package/dist/commands/doctor-parity.d.ts.map +1 -1
  10. package/dist/commands/doctor-parity.js +57 -1
  11. package/dist/commands/doctor-parity.js.map +1 -1
  12. package/dist/commands/eject.d.ts.map +1 -1
  13. package/dist/commands/eject.js +3 -0
  14. package/dist/commands/eject.js.map +1 -1
  15. package/dist/commands/init-templates.d.ts +15 -0
  16. package/dist/commands/init-templates.d.ts.map +1 -1
  17. package/dist/commands/init-templates.js +183 -2
  18. package/dist/commands/init-templates.js.map +1 -1
  19. package/dist/commands/init.d.ts.map +1 -1
  20. package/dist/commands/init.js +30 -2
  21. package/dist/commands/init.js.map +1 -1
  22. package/dist/commands/init.test.js +264 -1
  23. package/dist/commands/init.test.js.map +1 -1
  24. package/dist/commands/install-hooks-exit-contract.test.js +107 -3
  25. package/dist/commands/install-hooks-exit-contract.test.js.map +1 -1
  26. package/dist/commands/install-hooks.d.ts +39 -0
  27. package/dist/commands/install-hooks.d.ts.map +1 -1
  28. package/dist/commands/install-hooks.js +152 -0
  29. package/dist/commands/install-hooks.js.map +1 -1
  30. package/dist/commands/pr.d.ts +130 -0
  31. package/dist/commands/pr.d.ts.map +1 -0
  32. package/dist/commands/pr.js +427 -0
  33. package/dist/commands/pr.js.map +1 -0
  34. package/dist/commands/pr.test.d.ts +2 -0
  35. package/dist/commands/pr.test.d.ts.map +1 -0
  36. package/dist/commands/pr.test.js +494 -0
  37. package/dist/commands/pr.test.js.map +1 -0
  38. package/dist/index.js +34 -0
  39. package/dist/index.js.map +1 -1
  40. package/package.json +2 -2
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Network-read-only fetch edge for the Prop 296 §14 posture probes
3
+ * (mmnto-ai/totem-strategy#962). The CLI EDGE owns the network — core's
4
+ * `parity-detect.ts` keeps its module-wide never-networks + synchronous-pure
5
+ * invariant, so this module resolves the per-repo, per-surface SNAPSHOTS the
6
+ * pure detector then verdicts against.
7
+ *
8
+ * §14 hard edges honored here:
9
+ * 1. Read-only, ever — every request is an authenticated `gh api` GET; nothing
10
+ * mutates ([Tenet 13]).
11
+ * 2. Auth is the hard edge, rendered honestly — a missing/under-privileged
12
+ * token, an unreachable host, or a repo-scoped CI token that cannot see a
13
+ * sibling repo degrades to a per-SURFACE cannot-verify outcome
14
+ * (`auth`/`not-found`/`error`), never a drift verdict and never a
15
+ * manifest-wide outage. `no-transport` (gh absent / offline) is the distinct
16
+ * honest-absent (§14 clause 4) signal.
17
+ * 3. Per-repo verdict lines — the roster resolves one snapshot per repo; the
18
+ * current repo (derived from the LOCAL git remote — no network) is always in
19
+ * the roster, cross-repo reads are opt-in via `orient.parityProbeRepos`.
20
+ * 4. Offline degradation — gh unavailable ⇒ every surface `no-transport` ⇒
21
+ * every line renders as the honest-absent stub. NO retries.
22
+ *
23
+ * Transport is behind an INJECTABLE seam ({@link GhFetch}) so tests feed canned
24
+ * JSON and NEVER spawn `gh`. The default spawns `gh api` via `safeExec` (arg
25
+ * arrays, no `shell: true`, bounded timeout) — the git-subprocess pattern the
26
+ * core detectors already use.
27
+ */
28
+ import type { NetworkPostureRow, NetworkProbeRepoSnapshot, NetworkSurfaceOutcome } from '@mmnto/totem';
29
+ /** Resolve a contract id to its network-posture row kind, or undefined when unregistered. */
30
+ export declare function networkPostureRowFor(contractId: string): NetworkPostureRow | undefined;
31
+ /** One fetched surface plus its outcome — what {@link GhFetch} returns. */
32
+ export interface GhFetchResult {
33
+ outcome: NetworkSurfaceOutcome;
34
+ /** Parsed JSON body when `outcome === 'ok'`. */
35
+ data?: unknown;
36
+ /** Optional render detail (e.g. `HTTP 403`). */
37
+ detail?: string;
38
+ }
39
+ /**
40
+ * Injectable transport seam: issue one read-only GitHub API GET against
41
+ * `apiPath` (an absolute `/repos/...` path) from `cwd`. Tests inject a canned
42
+ * implementation; production omits it and the default spawns `gh api`.
43
+ */
44
+ export type GhFetch = (apiPath: string, cwd: string) => GhFetchResult;
45
+ /** Injectable local-remote reader (default `git remote get-url origin`). */
46
+ export type ReadRemote = (cwd: string) => string | undefined;
47
+ /** One network-posture row present in the manifest (id-derived row kind + its consumers scope). */
48
+ export interface NetworkRowSpec {
49
+ row: NetworkPostureRow;
50
+ consumers?: string[];
51
+ }
52
+ /** Options for {@link resolveNetworkSnapshots}. */
53
+ export interface ResolveNetworkSnapshotsOptions {
54
+ /** The network-posture rows present in the manifest (drives which surfaces to fetch). */
55
+ rows: NetworkRowSpec[];
56
+ /** Current repo's cohort id (for `consumers` scoping of the current-repo slug). */
57
+ repoId?: string;
58
+ /** The git root the local remote is read from + `gh` runs in. */
59
+ gitRoot: string;
60
+ /** Optional cross-repo read set (`orient.parityProbeRepos`), each an `owner/repo` slug. */
61
+ probeRepos?: string[];
62
+ /** Injectable transport (default spawns `gh api`). */
63
+ ghFetch?: GhFetch;
64
+ /** Injectable local-remote reader (default reads `git remote get-url origin`). */
65
+ readRemote?: ReadRemote;
66
+ }
67
+ /**
68
+ * Resolve the per-repo, per-surface snapshots the network-posture detector
69
+ * verdicts against. Fetches ONCE per (repo, surface) — the union of surfaces the
70
+ * in-scope rows need for each repo — with NO caching and NO retries. Never
71
+ * throws: a transport/auth failure becomes a per-surface outcome, never a crash.
72
+ *
73
+ * The function is async to keep the network step BEFORE the synchronous detector
74
+ * dispatch (the default transport is a synchronous `gh api` spawn; the async
75
+ * boundary future-proofs an async transport).
76
+ */
77
+ export declare function resolveNetworkSnapshots(options: ResolveNetworkSnapshotsOptions): Promise<NetworkProbeRepoSnapshot[]>;
78
+ /**
79
+ * Extract `owner/repo` from an ssh (`git@host:owner/repo.git`) or https
80
+ * (`https://host/owner/repo.git`) remote URL, tolerating a trailing `.git` and
81
+ * slashes. Returns undefined when no `owner/repo` pair resolves.
82
+ */
83
+ export declare function slugFromRemoteUrl(remoteUrl: string | undefined): string | undefined;
84
+ //# sourceMappingURL=doctor-parity-fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-parity-fetch.d.ts","sourceRoot":"","sources":["../../src/commands/doctor-parity-fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,wBAAwB,EAExB,qBAAqB,EAEtB,MAAM,cAAc,CAAC;AAkBtB,6FAA6F;AAC7F,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAEtF;AAED,2EAA2E;AAC3E,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,qBAAqB,CAAC;IAC/B,gDAAgD;IAChD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,aAAa,CAAC;AAEtE,4EAA4E;AAC5E,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;AAE7D,mGAAmG;AACnG,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,iBAAiB,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,mDAAmD;AACnD,MAAM,WAAW,8BAA8B;IAC7C,yFAAyF;IACzF,IAAI,EAAE,cAAc,EAAE,CAAC;IACvB,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,2FAA2F;IAC3F,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,sDAAsD;IACtD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kFAAkF;IAClF,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AA6BD;;;;;;;;;GASG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,8BAA8B,GACtC,OAAO,CAAC,wBAAwB,EAAE,CAAC,CA+BrC;AA+CD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAcnF"}
@@ -0,0 +1,367 @@
1
+ /**
2
+ * Network-read-only fetch edge for the Prop 296 §14 posture probes
3
+ * (mmnto-ai/totem-strategy#962). The CLI EDGE owns the network — core's
4
+ * `parity-detect.ts` keeps its module-wide never-networks + synchronous-pure
5
+ * invariant, so this module resolves the per-repo, per-surface SNAPSHOTS the
6
+ * pure detector then verdicts against.
7
+ *
8
+ * §14 hard edges honored here:
9
+ * 1. Read-only, ever — every request is an authenticated `gh api` GET; nothing
10
+ * mutates ([Tenet 13]).
11
+ * 2. Auth is the hard edge, rendered honestly — a missing/under-privileged
12
+ * token, an unreachable host, or a repo-scoped CI token that cannot see a
13
+ * sibling repo degrades to a per-SURFACE cannot-verify outcome
14
+ * (`auth`/`not-found`/`error`), never a drift verdict and never a
15
+ * manifest-wide outage. `no-transport` (gh absent / offline) is the distinct
16
+ * honest-absent (§14 clause 4) signal.
17
+ * 3. Per-repo verdict lines — the roster resolves one snapshot per repo; the
18
+ * current repo (derived from the LOCAL git remote — no network) is always in
19
+ * the roster, cross-repo reads are opt-in via `orient.parityProbeRepos`.
20
+ * 4. Offline degradation — gh unavailable ⇒ every surface `no-transport` ⇒
21
+ * every line renders as the honest-absent stub. NO retries.
22
+ *
23
+ * Transport is behind an INJECTABLE seam ({@link GhFetch}) so tests feed canned
24
+ * JSON and NEVER spawn `gh`. The default spawns `gh api` via `safeExec` (arg
25
+ * arrays, no `shell: true`, bounded timeout) — the git-subprocess pattern the
26
+ * core detectors already use.
27
+ */
28
+ /** Bounded per-request `gh api` timeout (mirrors orient's GH adapters). */
29
+ const GH_TIMEOUT_MS = 15_000;
30
+ /**
31
+ * The registry mapping a capability-probe contract id to its network-posture
32
+ * row kind (mirrors `capabilityProbesFor` with a `default: undefined` → the
33
+ * existing honest-skip stub). An unregistered id keeps the current
34
+ * capability-probe path untouched. The identity mapping is the routing seam:
35
+ * routing keys PRIMARILY on this id registry, not on the `probe-class` metadata.
36
+ */
37
+ const NETWORK_POSTURE_ROW_IDS = {
38
+ 'repo-merge-posture': 'repo-merge-posture',
39
+ 'repo-required-checks-posture': 'repo-required-checks-posture',
40
+ 'repo-branch-protection-posture': 'repo-branch-protection-posture',
41
+ };
42
+ /** Resolve a contract id to its network-posture row kind, or undefined when unregistered. */
43
+ export function networkPostureRowFor(contractId) {
44
+ return NETWORK_POSTURE_ROW_IDS[contractId];
45
+ }
46
+ /** Per-row surface requirements. */
47
+ function surfaceNeedsFor(row) {
48
+ switch (row) {
49
+ case 'repo-merge-posture':
50
+ return { repoSettings: true, rulesets: false, branchProtection: false };
51
+ case 'repo-required-checks-posture':
52
+ return { repoSettings: false, rulesets: true, branchProtection: false };
53
+ case 'repo-branch-protection-posture':
54
+ return { repoSettings: false, rulesets: true, branchProtection: true };
55
+ default:
56
+ return { repoSettings: false, rulesets: false, branchProtection: false };
57
+ }
58
+ }
59
+ /**
60
+ * Resolve the per-repo, per-surface snapshots the network-posture detector
61
+ * verdicts against. Fetches ONCE per (repo, surface) — the union of surfaces the
62
+ * in-scope rows need for each repo — with NO caching and NO retries. Never
63
+ * throws: a transport/auth failure becomes a per-surface outcome, never a crash.
64
+ *
65
+ * The function is async to keep the network step BEFORE the synchronous detector
66
+ * dispatch (the default transport is a synchronous `gh api` spawn; the async
67
+ * boundary future-proofs an async transport).
68
+ */
69
+ export async function resolveNetworkSnapshots(options) {
70
+ // Import `safeExec` once for the default transport/remote seams (idempotent,
71
+ // cached; the dynamic import matches the doctor's other lazy `@mmnto/totem`
72
+ // loads). When both seams are injected — the test path — the real spawn is
73
+ // never invoked, so no `gh`/`git` subprocess runs.
74
+ const { safeExec } = await import('@mmnto/totem');
75
+ const ghFetch = options.ghFetch ?? makeDefaultGhFetch(safeExec);
76
+ const readRemote = options.readRemote ?? makeDefaultReadRemote(safeExec);
77
+ const roster = resolveRoster(options, readRemote);
78
+ const snapshots = [];
79
+ for (const entry of roster) {
80
+ // Per-repo needed surfaces = union over the rows in scope for THIS repo
81
+ // (a `consumers: [totem]` row contributes its surfaces only to totem).
82
+ const need = { repoSettings: false, rulesets: false, branchProtection: false };
83
+ for (const spec of options.rows) {
84
+ if (spec.consumers !== undefined && !spec.consumers.includes(entry.repoId))
85
+ continue;
86
+ const rowNeed = surfaceNeedsFor(spec.row);
87
+ need.repoSettings ||= rowNeed.repoSettings;
88
+ need.rulesets ||= rowNeed.rulesets;
89
+ need.branchProtection ||= rowNeed.branchProtection;
90
+ }
91
+ if (!need.repoSettings && !need.rulesets && !need.branchProtection)
92
+ continue;
93
+ snapshots.push({
94
+ repoSlug: entry.repoSlug,
95
+ repoId: entry.repoId,
96
+ surfaces: fetchSurfaces(entry.repoSlug, need, ghFetch, options.gitRoot),
97
+ });
98
+ }
99
+ return snapshots;
100
+ }
101
+ /** Build the roster: the current repo (local-remote-derived) plus any opt-in cross-repo slugs. */
102
+ function resolveRoster(options, readRemote) {
103
+ const entries = [];
104
+ const seen = new Set();
105
+ const currentSlug = deriveCurrentSlug(options, readRemote);
106
+ if (currentSlug !== undefined) {
107
+ entries.push({ repoSlug: currentSlug, repoId: options.repoId ?? repoSegment(currentSlug) });
108
+ seen.add(currentSlug);
109
+ }
110
+ for (const raw of options.probeRepos ?? []) {
111
+ const slug = raw.trim();
112
+ if (slug.length === 0 || seen.has(slug))
113
+ continue;
114
+ // A cross-repo entry's cohort id is the repo segment of its own slug.
115
+ entries.push({ repoSlug: slug, repoId: repoSegment(slug) });
116
+ seen.add(slug);
117
+ }
118
+ return entries;
119
+ }
120
+ /** Derive the current repo's `owner/repo` slug from the LOCAL git remote (no network). */
121
+ function deriveCurrentSlug(options, readRemote) {
122
+ let url;
123
+ try {
124
+ url = readRemote(options.gitRoot);
125
+ // totem-context: a missing remote / non-git dir / absent git binary is a routine fall-through (the current repo is simply not probed), not a sensor failure.
126
+ }
127
+ catch {
128
+ url = undefined;
129
+ }
130
+ return slugFromRemoteUrl(url);
131
+ }
132
+ /** The repo segment of an `owner/repo` slug (the cohort id). */
133
+ function repoSegment(slug) {
134
+ const parts = slug.split('/');
135
+ return parts[parts.length - 1] ?? slug;
136
+ }
137
+ /**
138
+ * Extract `owner/repo` from an ssh (`git@host:owner/repo.git`) or https
139
+ * (`https://host/owner/repo.git`) remote URL, tolerating a trailing `.git` and
140
+ * slashes. Returns undefined when no `owner/repo` pair resolves.
141
+ */
142
+ export function slugFromRemoteUrl(remoteUrl) {
143
+ if (typeof remoteUrl !== 'string' || remoteUrl.trim().length === 0)
144
+ return undefined;
145
+ const trimmed = remoteUrl
146
+ .trim()
147
+ .replace(/\.git$/i, '')
148
+ .replace(/\/+$/, '');
149
+ const match = /[/:]([^/:]+)\/([^/]+)$/.exec(trimmed);
150
+ if (match === null)
151
+ return undefined;
152
+ const owner = match[1];
153
+ const repo = match[2];
154
+ if (owner === undefined || repo === undefined || owner.length === 0 || repo.length === 0) {
155
+ return undefined;
156
+ }
157
+ return `${owner}/${repo}`;
158
+ }
159
+ /** Fetch the union of needed surfaces for one repo. */
160
+ function fetchSurfaces(slug, need, ghFetch, cwd) {
161
+ const surfaces = {};
162
+ // Repo settings double as the source of `default_branch` for classic branch
163
+ // protection, so fetch it whenever either surface is needed.
164
+ let repoResult;
165
+ if (need.repoSettings || need.branchProtection) {
166
+ repoResult = ghFetch(`/repos/${slug}`, cwd);
167
+ }
168
+ if (need.repoSettings && repoResult !== undefined) {
169
+ surfaces.repoSettings = toSnapshot(repoResult);
170
+ }
171
+ if (need.rulesets) {
172
+ surfaces.rulesets = fetchRulesetsSurface(slug, ghFetch, cwd);
173
+ }
174
+ if (need.branchProtection) {
175
+ surfaces.branchProtection = fetchBranchProtectionSurface(slug, repoResult, ghFetch, cwd);
176
+ }
177
+ return surfaces;
178
+ }
179
+ /** Narrow a {@link GhFetchResult} to a {@link NetworkSurfaceSnapshot}. */
180
+ function toSnapshot(result) {
181
+ return {
182
+ outcome: result.outcome,
183
+ ...(result.data !== undefined ? { data: result.data } : {}),
184
+ ...(result.detail !== undefined ? { detail: result.detail } : {}),
185
+ };
186
+ }
187
+ /**
188
+ * The rulesets surface: list the repo's rulesets, then fetch each one's DETAIL
189
+ * (the list omits conditions/rules/bypass_actors). The detail array is the
190
+ * surface `data`. A list-level failure propagates its outcome; a per-detail 404
191
+ * (ruleset deleted mid-read) is skipped; any other per-detail failure propagates
192
+ * (conservative — a partial read cannot certify the union).
193
+ */
194
+ function fetchRulesetsSurface(slug, ghFetch, cwd) {
195
+ // per_page=100 (the API max). Deliberately NOT `--paginate`: paged gh output
196
+ // concatenates JSON documents (or needs --slurp, a newer-gh dependency); the
197
+ // boundary sentinel below keeps the never-silently-undercount invariant
198
+ // instead (CR round 1) — a repo at the cap degrades to cannot-verify, never
199
+ // to a partial union.
200
+ const list = ghFetch(`/repos/${slug}/rulesets?includes_parents=true&per_page=100`, cwd);
201
+ if (list.outcome !== 'ok')
202
+ return toSnapshot(list);
203
+ // A non-array 200 payload must degrade to cannot-verify — coercing it to []
204
+ // would let the detector certify "no rulesets" from garbage (greptile P1).
205
+ if (!Array.isArray(list.data)) {
206
+ return { outcome: 'error', detail: 'unparseable rulesets list response' };
207
+ }
208
+ const summaries = list.data;
209
+ if (summaries.length >= 100) {
210
+ return {
211
+ outcome: 'error',
212
+ detail: 'rulesets list at the pagination boundary (100) — possible truncation, cannot certify the union',
213
+ };
214
+ }
215
+ const details = [];
216
+ for (const summary of summaries) {
217
+ const id = rulesetId(summary);
218
+ if (id === undefined) {
219
+ // An id-less entry cannot be detail-fetched — a partial read cannot
220
+ // certify the union (same posture as the per-detail failure below).
221
+ return {
222
+ outcome: 'error',
223
+ detail: 'ruleset list entry without a usable id — cannot enumerate the union',
224
+ };
225
+ }
226
+ const detail = ghFetch(`/repos/${slug}/rulesets/${id}`, cwd);
227
+ if (detail.outcome === 'ok') {
228
+ details.push(detail.data);
229
+ continue;
230
+ }
231
+ if (detail.outcome === 'not-found')
232
+ continue; // deleted mid-read — omit
233
+ // A non-404 per-detail failure means we cannot fully enumerate the union.
234
+ return {
235
+ outcome: detail.outcome,
236
+ ...(detail.detail !== undefined ? { detail: detail.detail } : {}),
237
+ };
238
+ }
239
+ return { outcome: 'ok', data: details };
240
+ }
241
+ /** Extract a ruleset id from a list-summary object. */
242
+ function rulesetId(summary) {
243
+ if (typeof summary !== 'object' || summary === null)
244
+ return undefined;
245
+ const id = summary.id;
246
+ return typeof id === 'number' || typeof id === 'string' ? id : undefined;
247
+ }
248
+ /**
249
+ * The classic-branch-protection surface: `GET …/branches/{default_branch}/protection`.
250
+ * The default branch comes from the repo-settings read; when that read failed (or
251
+ * omitted `default_branch`), the branch is unaddressable → propagate the
252
+ * repo-settings failure (or an auth-class `unknown` for a field-shy 200).
253
+ */
254
+ function fetchBranchProtectionSurface(slug, repoResult, ghFetch, cwd) {
255
+ if (repoResult === undefined) {
256
+ return { outcome: 'error', detail: 'repo settings unavailable — default branch unresolved' };
257
+ }
258
+ if (repoResult.outcome !== 'ok')
259
+ return toSnapshot(repoResult);
260
+ const defaultBranch = defaultBranchOf(repoResult.data);
261
+ if (defaultBranch === undefined) {
262
+ return {
263
+ outcome: 'auth',
264
+ detail: 'repo 200 without default_branch — cannot address branch protection (auth-class)',
265
+ };
266
+ }
267
+ const encoded = defaultBranch
268
+ .split('/')
269
+ .map((seg) => encodeURIComponent(seg))
270
+ .join('/');
271
+ return toSnapshot(ghFetch(`/repos/${slug}/branches/${encoded}/protection`, cwd));
272
+ }
273
+ /** Read `default_branch` from a repo-settings payload, or undefined when absent/mis-typed. */
274
+ function defaultBranchOf(data) {
275
+ if (typeof data !== 'object' || data === null)
276
+ return undefined;
277
+ const branch = data.default_branch;
278
+ return typeof branch === 'string' && branch.length > 0 ? branch : undefined;
279
+ }
280
+ /**
281
+ * Build the default {@link GhFetch}: spawn `gh api <path>` via `safeExec` (arg
282
+ * array, no shell, bounded timeout) and classify the outcome. `safeExec` is
283
+ * injected (imported once in {@link resolveNetworkSnapshots}) so this module
284
+ * stays ESM-clean and test-injectable.
285
+ */
286
+ function makeDefaultGhFetch(safeExec) {
287
+ return (apiPath, cwd) => {
288
+ let raw;
289
+ try {
290
+ raw = safeExec('gh', ['api', apiPath, '-H', 'Accept: application/vnd.github+json'], {
291
+ cwd,
292
+ timeout: GH_TIMEOUT_MS,
293
+ env: { ...process.env, GH_PROMPT_DISABLED: '1' },
294
+ });
295
+ // totem-context: a gh failure (no token, 4xx/5xx, offline, gh absent) is classified into a per-surface outcome (§14 clause 2/4), never rethrown — the sensor must degrade honestly, not crash.
296
+ }
297
+ catch (err) {
298
+ return classifyGhError(err);
299
+ }
300
+ try {
301
+ return { outcome: 'ok', data: JSON.parse(raw) };
302
+ // totem-context: an unparseable 200 body is a transient `error` outcome (→ unknown), not a throw.
303
+ }
304
+ catch {
305
+ return { outcome: 'error', detail: 'unparseable gh api response' };
306
+ }
307
+ };
308
+ }
309
+ /**
310
+ * Classify a `gh api` failure into a network-read-only outcome (§14 clause 2/4):
311
+ * - spawn failure (gh absent) → `no-transport` (offline honest-absent).
312
+ * - 401 / bad credentials / not-authenticated → `auth`.
313
+ * - 403 → `auth` unless it is a rate-limit (→ `error`, transient).
314
+ * - 404 → `not-found`.
315
+ * - 5xx / timeout / DNS → `error`.
316
+ * - anything else → `error` (transient), never a drift verdict.
317
+ */
318
+ function classifyGhError(err) {
319
+ const e = (err ?? {});
320
+ const stderr = `${e.stderr ?? ''} ${e.message ?? ''}`.toLowerCase();
321
+ if (isSpawnFailure(e)) {
322
+ return { outcome: 'no-transport', detail: 'gh not found — offline (§14 clause 4)' };
323
+ }
324
+ if (/http 401|bad credentials|requires authentication|gh auth login|not logged in/.test(stderr)) {
325
+ return { outcome: 'auth', detail: 'HTTP 401 / not authenticated' };
326
+ }
327
+ if (/http 403/.test(stderr)) {
328
+ return /rate limit/.test(stderr)
329
+ ? { outcome: 'error', detail: 'HTTP 403 rate limited' }
330
+ : { outcome: 'auth', detail: 'HTTP 403 — under-privileged token' };
331
+ }
332
+ if (/http 404|not found/.test(stderr)) {
333
+ return { outcome: 'not-found', detail: 'HTTP 404' };
334
+ }
335
+ if (/http 5\d\d|timeout|timed out|could not resolve host|network is unreachable|econnreset|dial tcp/.test(stderr)) {
336
+ return { outcome: 'error', detail: 'transient / unreachable host' };
337
+ }
338
+ // A gh with no token at all often reports an auth hint without an HTTP code.
339
+ if (/authentication|gh auth|no token|token/.test(stderr)) {
340
+ return { outcome: 'auth', detail: 'not authenticated' };
341
+ }
342
+ return { outcome: 'error', detail: 'gh api failed' };
343
+ }
344
+ /** True when the throw is a spawn-level failure (gh binary missing), not an HTTP error. */
345
+ function isSpawnFailure(e) {
346
+ const causeCode = typeof e.cause === 'object' && e.cause !== null
347
+ ? e.cause.code
348
+ : undefined;
349
+ if (causeCode === 'ENOENT')
350
+ return true;
351
+ const msg = `${e.message ?? ''}`;
352
+ // safeExec renders a spawn-level failure as `…: spawn failed` (no HTTP status).
353
+ return /enoent|spawn failed/i.test(msg) && !/http \d{3}/i.test(msg);
354
+ }
355
+ /** Build the default local-remote reader: `git remote get-url origin` (swallowed to undefined on failure). */
356
+ function makeDefaultReadRemote(safeExec) {
357
+ return (cwd) => {
358
+ try {
359
+ return safeExec('git', ['remote', 'get-url', 'origin'], { cwd, timeout: GH_TIMEOUT_MS });
360
+ // totem-context: a missing remote / non-git dir / absent git binary is a routine fall-through (the current repo is simply not probed), not a sensor failure.
361
+ }
362
+ catch {
363
+ return undefined;
364
+ }
365
+ };
366
+ }
367
+ //# sourceMappingURL=doctor-parity-fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-parity-fetch.js","sourceRoot":"","sources":["../../src/commands/doctor-parity-fetch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Tests for the §14 network-read-only fetch edge (`doctor-parity-fetch.ts`,
3
+ * strategy#962).
4
+ *
5
+ * Every test injects the transport ({@link GhFetch}) AND the local-remote reader
6
+ * ({@link ReadRemote}) seams, so NO `gh`/`git` subprocess ever spawns and there
7
+ * is zero live network. The suite covers: slug derivation, the roster (current +
8
+ * opt-in cross-repo, dedup), per-repo surface selection under consumers scoping,
9
+ * the rulesets list→detail assembly, branch-protection default-branch resolution,
10
+ * and the no-remote / no-transport degradations.
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=doctor-parity-fetch.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-parity-fetch.test.d.ts","sourceRoot":"","sources":["../../src/commands/doctor-parity-fetch.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}