@runcofactor/cli 0.10.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 (150) hide show
  1. package/README.md +125 -0
  2. package/dist/api-catalog-GFGCLVS4.js +401 -0
  3. package/dist/api-catalog-GFGCLVS4.js.map +1 -0
  4. package/dist/attachment-SJC7D7FY.js +276 -0
  5. package/dist/attachment-SJC7D7FY.js.map +1 -0
  6. package/dist/auth-EN6NQCJY.js +31 -0
  7. package/dist/auth-EN6NQCJY.js.map +1 -0
  8. package/dist/bin.js +7 -0
  9. package/dist/bin.js.map +1 -0
  10. package/dist/chunk-3CZU7XCS.js +272 -0
  11. package/dist/chunk-3CZU7XCS.js.map +1 -0
  12. package/dist/chunk-4NRDONSC.js +1048 -0
  13. package/dist/chunk-4NRDONSC.js.map +1 -0
  14. package/dist/chunk-4PNOV7OV.js +51980 -0
  15. package/dist/chunk-4PNOV7OV.js.map +1 -0
  16. package/dist/chunk-52IO7ACJ.js +2941 -0
  17. package/dist/chunk-52IO7ACJ.js.map +1 -0
  18. package/dist/chunk-6LEZCKKV.js +663 -0
  19. package/dist/chunk-6LEZCKKV.js.map +1 -0
  20. package/dist/chunk-A4OFTUVV.js +170 -0
  21. package/dist/chunk-A4OFTUVV.js.map +1 -0
  22. package/dist/chunk-B2VISN2V.js +2459 -0
  23. package/dist/chunk-B2VISN2V.js.map +1 -0
  24. package/dist/chunk-CLAWT7BJ.js +271 -0
  25. package/dist/chunk-CLAWT7BJ.js.map +1 -0
  26. package/dist/chunk-GKY2KXO5.js +281 -0
  27. package/dist/chunk-GKY2KXO5.js.map +1 -0
  28. package/dist/chunk-I4QLI3JO.js +413 -0
  29. package/dist/chunk-I4QLI3JO.js.map +1 -0
  30. package/dist/chunk-IMPZAX6L.js +180 -0
  31. package/dist/chunk-IMPZAX6L.js.map +1 -0
  32. package/dist/chunk-J6SH7GQT.js +241 -0
  33. package/dist/chunk-J6SH7GQT.js.map +1 -0
  34. package/dist/chunk-JDBCZ3Z2.js +298 -0
  35. package/dist/chunk-JDBCZ3Z2.js.map +1 -0
  36. package/dist/chunk-JICSYFRJ.js +46 -0
  37. package/dist/chunk-JICSYFRJ.js.map +1 -0
  38. package/dist/chunk-JWHYXEA2.js +32 -0
  39. package/dist/chunk-JWHYXEA2.js.map +1 -0
  40. package/dist/chunk-N7HFALX3.js +88 -0
  41. package/dist/chunk-N7HFALX3.js.map +1 -0
  42. package/dist/chunk-Q4BO4Z5V.js +178 -0
  43. package/dist/chunk-Q4BO4Z5V.js.map +1 -0
  44. package/dist/chunk-QFDOWABX.js +195 -0
  45. package/dist/chunk-QFDOWABX.js.map +1 -0
  46. package/dist/chunk-SJJW77WN.js +605 -0
  47. package/dist/chunk-SJJW77WN.js.map +1 -0
  48. package/dist/chunk-VKVL7WBN.js +50 -0
  49. package/dist/chunk-VKVL7WBN.js.map +1 -0
  50. package/dist/chunk-WOHL4FTB.js +353 -0
  51. package/dist/chunk-WOHL4FTB.js.map +1 -0
  52. package/dist/chunk-XQXVG7RA.js +426 -0
  53. package/dist/chunk-XQXVG7RA.js.map +1 -0
  54. package/dist/chunk-ZD3KHESI.js +94 -0
  55. package/dist/chunk-ZD3KHESI.js.map +1 -0
  56. package/dist/credential-COLTBV6D.js +450 -0
  57. package/dist/credential-COLTBV6D.js.map +1 -0
  58. package/dist/credential-template-EEPYFG7R.js +291 -0
  59. package/dist/credential-template-EEPYFG7R.js.map +1 -0
  60. package/dist/debug-workflow-KOVH5GOP.js +259 -0
  61. package/dist/debug-workflow-KOVH5GOP.js.map +1 -0
  62. package/dist/dist-44PZR7BQ.js +423 -0
  63. package/dist/dist-44PZR7BQ.js.map +1 -0
  64. package/dist/docs-3SSORHB5.js +366 -0
  65. package/dist/docs-3SSORHB5.js.map +1 -0
  66. package/dist/doctor-OTSIWV6G.js +132 -0
  67. package/dist/doctor-OTSIWV6G.js.map +1 -0
  68. package/dist/feature-flag-T2LRZME3.js +283 -0
  69. package/dist/feature-flag-T2LRZME3.js.map +1 -0
  70. package/dist/file-type-S3UUBVCT.js +4205 -0
  71. package/dist/file-type-S3UUBVCT.js.map +1 -0
  72. package/dist/index.d.ts +3 -0
  73. package/dist/index.js +982 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/init-TGWRECT2.js +208 -0
  76. package/dist/init-TGWRECT2.js.map +1 -0
  77. package/dist/install-DXSNWZKO.js +295 -0
  78. package/dist/install-DXSNWZKO.js.map +1 -0
  79. package/dist/issues-XIZOPX6T.js +564 -0
  80. package/dist/issues-XIZOPX6T.js.map +1 -0
  81. package/dist/knobs-NBINZIUB.js +295 -0
  82. package/dist/knobs-NBINZIUB.js.map +1 -0
  83. package/dist/list-3TDHK637.js +59 -0
  84. package/dist/list-3TDHK637.js.map +1 -0
  85. package/dist/local-HICVD6PU.js +100 -0
  86. package/dist/local-HICVD6PU.js.map +1 -0
  87. package/dist/login-UOIUXVUK.js +315 -0
  88. package/dist/login-UOIUXVUK.js.map +1 -0
  89. package/dist/mcp-54IJEOUA.js +1956 -0
  90. package/dist/mcp-54IJEOUA.js.map +1 -0
  91. package/dist/pdf-extract-ABWV3L5X.js +13 -0
  92. package/dist/pdf-extract-ABWV3L5X.js.map +1 -0
  93. package/dist/pdfjs-DQ2YA5S3.js +41561 -0
  94. package/dist/pdfjs-DQ2YA5S3.js.map +1 -0
  95. package/dist/property-UXLOLPTD.js +701 -0
  96. package/dist/property-UXLOLPTD.js.map +1 -0
  97. package/dist/property-skill-guide.md +189 -0
  98. package/dist/psql-BYUUNLGG.js +115 -0
  99. package/dist/psql-BYUUNLGG.js.map +1 -0
  100. package/dist/record-4TR2UIIS.js +233 -0
  101. package/dist/record-4TR2UIIS.js.map +1 -0
  102. package/dist/redis-35VBUYW7.js +116 -0
  103. package/dist/redis-35VBUYW7.js.map +1 -0
  104. package/dist/release-OOLTUBUT.js +354 -0
  105. package/dist/release-OOLTUBUT.js.map +1 -0
  106. package/dist/sandbox-XGSUU6G7.js +2046 -0
  107. package/dist/sandbox-XGSUU6G7.js.map +1 -0
  108. package/dist/scenarios-GWLJEGHA.js +280 -0
  109. package/dist/scenarios-GWLJEGHA.js.map +1 -0
  110. package/dist/session-MYFNZPRP.js +2414 -0
  111. package/dist/session-MYFNZPRP.js.map +1 -0
  112. package/dist/skill-KM34LDMO.js +1839 -0
  113. package/dist/skill-KM34LDMO.js.map +1 -0
  114. package/dist/skills/debug-run/SKILL.md +262 -0
  115. package/dist/skills/debug-run/history/1.0.0.md +244 -0
  116. package/dist/skills/debug-run/history/1.0.1.md +245 -0
  117. package/dist/skills/debug-run/history/1.0.2.md +254 -0
  118. package/dist/skills/debug-run/history/1.1.0.md +262 -0
  119. package/dist/skills/debug-run/version.json +3 -0
  120. package/dist/spec-RA3CFEKG.js +951 -0
  121. package/dist/spec-RA3CFEKG.js.map +1 -0
  122. package/dist/src-LB4HBTJQ.js +1516 -0
  123. package/dist/src-LB4HBTJQ.js.map +1 -0
  124. package/dist/src-N3TPKGTY.js +244 -0
  125. package/dist/src-N3TPKGTY.js.map +1 -0
  126. package/dist/src-UVDX5UP6.js +17 -0
  127. package/dist/src-UVDX5UP6.js.map +1 -0
  128. package/dist/start-PSEQSQA3.js +151 -0
  129. package/dist/start-PSEQSQA3.js.map +1 -0
  130. package/dist/tag-YY6YAABQ.js +22 -0
  131. package/dist/tag-YY6YAABQ.js.map +1 -0
  132. package/dist/task-IQC3YR5K.js +922 -0
  133. package/dist/task-IQC3YR5K.js.map +1 -0
  134. package/dist/test-suite-DZNJFXDW.js +394 -0
  135. package/dist/test-suite-DZNJFXDW.js.map +1 -0
  136. package/dist/trace-HXIW7U2D.js +14 -0
  137. package/dist/trace-HXIW7U2D.js.map +1 -0
  138. package/dist/triage-ORG45R5W.js +16 -0
  139. package/dist/triage-ORG45R5W.js.map +1 -0
  140. package/dist/upgrade-L2VYMP2V.js +61 -0
  141. package/dist/upgrade-L2VYMP2V.js.map +1 -0
  142. package/dist/workflow-XYFH5LTP.js +3708 -0
  143. package/dist/workflow-XYFH5LTP.js.map +1 -0
  144. package/dist/workflow-cache-NQJQFWMV.js +253 -0
  145. package/dist/workflow-cache-NQJQFWMV.js.map +1 -0
  146. package/dist/workflow-debug-BGD4UIXU.js +927 -0
  147. package/dist/workflow-debug-BGD4UIXU.js.map +1 -0
  148. package/dist/workflow-proposals-MTUDX46O.js +382 -0
  149. package/dist/workflow-proposals-MTUDX46O.js.map +1 -0
  150. package/package.json +61 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/jwt.ts","../src/api-fetch.ts"],"sourcesContent":["/**\n * JWT payload decoder for CLI superadmin detection.\n *\n * Decodes the payload section of a JWT locally (no signature verification,\n * no network calls). Used to conditionally show superadmin CLI commands.\n *\n * @module\n */\n\n/**\n * Decode the payload (second segment) of a JWT without verifying the signature.\n * Returns the parsed JSON object, or `null` if the token is malformed.\n */\nexport function decodeJwtPayload(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3) return null;\n\n const base64 = parts[1]!.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const json = Buffer.from(base64, \"base64\").toString(\"utf8\");\n const payload: unknown = JSON.parse(json);\n\n if (typeof payload !== \"object\" || payload === null || Array.isArray(payload)) {\n return null;\n }\n return payload as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\n/**\n * Returns `true` when the JWT's `is_superadmin` claim is exactly `true`.\n * Returns `false` for any invalid, missing, or non-superadmin token.\n */\nexport function isSuperadminToken(token: string | null | undefined): boolean {\n if (!token) return false;\n const payload = decodeJwtPayload(token);\n return payload?.is_superadmin === true;\n}\n","/**\n * Central fetch wrapper for the Canary CLI.\n *\n * Exists to classify failures so corporate-proxy interference (Zscaler,\n * Netskope, Cloudflare Access, etc.) is distinguishable from real auth\n * expiry. Every non-2xx or transport error gets a specific, actionable\n * message instead of the historical blanket \"session may have expired.\"\n *\n * Set CANARY_DEBUG=1 (or pass --debug to the CLI) to log every request\n * and its classification — this is what affected users should share\n * with us or their IT/Zscaler admin.\n */\n\nimport process from 'node:process';\nimport { decodeJwtPayload } from './jwt.js';\n\n/** Header every canary API response carries. Absence => response did not come from our API. */\nconst CANARY_REQUEST_ID_HEADER = 'x-canary-request-id';\n\n/** Default per-request timeout. Zscaler-half-opened sockets have been observed\n * hanging indefinitely; the CLI should give up and classify rather than hang. */\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/** Treat a JWT exp within this grace window as still valid — tolerates the\n * typical handful of seconds of client-clock skew so we don't mislabel a\n * 30-second-fast clock as `token-revoked`. */\nconst JWT_EXP_SKEW_SEC = 60;\n\n/**\n * Best-effort scrub of `Bearer <token>` and bare three-segment JWTs from\n * error text before we print it. Doctor output is explicitly coached to be\n * shared with IT — if a proxy block page reflects the Authorization header,\n * we do not want the token in that paste.\n */\nfunction redactSecrets(text: string): string {\n return text\n .replace(/Bearer\\s+[A-Za-z0-9._-]+/gi, 'Bearer [redacted]')\n .replace(/\\beyJ[A-Za-z0-9_-]{6,}\\.[A-Za-z0-9_-]{6,}\\.[A-Za-z0-9_-]{6,}\\b/g, '[redacted-jwt]');\n}\n\n/** Strip query string — query params sometimes carry one-time tokens. */\nfunction redactUrl(url: string): string {\n const q = url.indexOf('?');\n return q === -1 ? url : `${url.slice(0, q)}?[redacted]`;\n}\n\nexport type FailureKind =\n | 'tls'\n | 'network'\n | 'html-body'\n | 'proxy-injected-4xx'\n | 'token-revoked'\n | 'token-expired'\n | 'unauthorized'\n | 'http-error';\n\nexport interface ClassifiedFailure {\n kind: FailureKind;\n status: number | null;\n url: string;\n message: string;\n /**\n * Response body text. Full body for `http-error` (so callers can parse\n * structured error payloads); truncated snippet for proxy/TLS failures\n * where the body is likely an HTML block page.\n */\n body?: string;\n /** Best-effort content-type. */\n contentType?: string;\n /** Raw error object for transport failures. */\n cause?: unknown;\n /**\n * Value of `x-canary-request-id` on the response, if any. Present means\n * the response came from our API (even for `token-revoked` / `token-expired`\n * / `unauthorized`); absent means the response was injected or the request\n * never reached us.\n */\n requestId?: string | null;\n}\n\nfunction isDebug(): boolean {\n return (\n process.env.CANARY_DEBUG === '1' ||\n process.env.CANARY_DEBUG === 'true' ||\n process.argv.includes('--debug')\n );\n}\n\nfunction debug(line: string): void {\n if (isDebug()) {\n process.stderr.write(`[canary-debug] ${line}\\n`);\n }\n}\n\n/**\n * Node/undici TLS error codes that indicate a MITM proxy (Zscaler et al.)\n * is intercepting HTTPS without the user trusting the proxy's root CA.\n */\nconst TLS_CODES = new Set([\n 'UNABLE_TO_VERIFY_LEAF_SIGNATURE',\n 'UNABLE_TO_GET_ISSUER_CERT',\n 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY',\n 'SELF_SIGNED_CERT_IN_CHAIN',\n 'DEPTH_ZERO_SELF_SIGNED_CERT',\n 'CERT_HAS_EXPIRED',\n 'CERT_UNTRUSTED',\n 'ERR_TLS_CERT_ALTNAME_INVALID',\n 'CERT_SIGNATURE_FAILURE',\n]);\n\nfunction extractErrorCode(err: unknown): string | null {\n if (!err || typeof err !== 'object') return null;\n const withCode = err as { code?: unknown; cause?: unknown };\n if (typeof withCode.code === 'string') return withCode.code;\n if (withCode.cause) return extractErrorCode(withCode.cause);\n return null;\n}\n\nfunction looksLikeHtml(body: string, contentType: string | null): boolean {\n if (contentType && contentType.toLowerCase().includes('text/html')) return true;\n const trimmed = body.trimStart();\n return trimmed.startsWith('<!') || trimmed.startsWith('<html') || trimmed.startsWith('<HTML');\n}\n\n/** Decode JWT `exp` and compare to now (with a small skew grace); null if undecodable. */\nfunction jwtExpStatus(token: string | undefined): 'expired' | 'valid' | 'unknown' {\n if (!token) return 'unknown';\n const payload = decodeJwtPayload(token);\n const exp = payload && typeof payload.exp === 'number' ? (payload.exp as number) : null;\n if (exp === null) return 'unknown';\n const nowSec = Math.floor(Date.now() / 1000);\n return exp < nowSec - JWT_EXP_SKEW_SEC ? 'expired' : 'valid';\n}\n\n/** Warn once per process when sending Authorization to a non-local http:// URL. */\nlet warnedAboutPlaintext = false;\nfunction maybeWarnPlaintextAuth(url: string, hasAuthHeader: boolean): void {\n if (!hasAuthHeader || warnedAboutPlaintext) return;\n if (!url.startsWith('http://')) return;\n try {\n const host = new URL(url).hostname;\n if (host === 'localhost' || host === '127.0.0.1' || host === '::1') return;\n } catch {\n return;\n }\n warnedAboutPlaintext = true;\n process.stderr.write(\n `[canary] WARNING: sending Authorization over plaintext http:// (${url}). ` +\n 'Your API token may be exposed to the network. Use https:// in CANARY_API_URL.\\n'\n );\n}\n\nfunction hasAuthHeader(init: RequestInit): boolean {\n const h = init.headers;\n if (!h) return false;\n if (h instanceof Headers) return h.has('authorization');\n if (Array.isArray(h)) return h.some(([k]) => k.toLowerCase() === 'authorization');\n return Object.keys(h).some((k) => k.toLowerCase() === 'authorization');\n}\n\n/**\n * Wrap global `fetch` with classification. Always resolves — never throws —\n * so callers can make a single uniform decision from the returned shape.\n */\nexport async function apiFetch(\n url: string,\n init: RequestInit & { token?: string; timeoutMs?: number } = {}\n): Promise<\n | { ok: true; response: Response; requestId: string | null }\n | { ok: false; failure: ClassifiedFailure }\n> {\n const { token, timeoutMs, ...fetchInit } = init;\n maybeWarnPlaintextAuth(url, hasAuthHeader(fetchInit));\n debug(`→ ${fetchInit.method ?? 'GET'} ${redactUrl(url)}`);\n\n // Merge caller-supplied signal with our timeout so both can abort.\n // timeoutMs <= 0 disables the timeout (use for long-lived SSE streams).\n const timeout = timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const timeoutSignal = timeout > 0 ? AbortSignal.timeout(timeout) : null;\n const effectiveSignal =\n fetchInit.signal && timeoutSignal\n ? AbortSignal.any([fetchInit.signal, timeoutSignal])\n : (fetchInit.signal ?? timeoutSignal ?? undefined);\n\n let response: Response;\n try {\n response = await fetch(url, { ...fetchInit, signal: effectiveSignal });\n } catch (err) {\n const isTimeout =\n (err as { name?: string })?.name === 'TimeoutError' ||\n Boolean(timeoutSignal?.aborted);\n if (isTimeout) {\n const msg = `Request to ${redactUrl(url)} timed out after ${timeout}ms.`;\n debug(`✖ network timeout`);\n return {\n ok: false,\n failure: { kind: 'network', status: null, url, message: msg, cause: err },\n };\n }\n const code = extractErrorCode(err);\n if (code && TLS_CODES.has(code)) {\n const msg = [\n `TLS verification failed talking to ${redactUrl(url)} (${code}).`,\n 'A corporate proxy (Zscaler, Netskope, ZPA, Cloudflare Access) is likely intercepting HTTPS.',\n 'Fixes: point Node at the proxy\\'s root CA with',\n ' NODE_EXTRA_CA_CERTS=/path/to/corporate-root.pem canary …',\n 'or on Node 20+ enable the system trust store with',\n ' NODE_OPTIONS=--use-system-ca canary …',\n ].join('\\n');\n debug(`✖ tls ${code}`);\n return { ok: false, failure: { kind: 'tls', status: null, url, message: msg, cause: err } };\n }\n const msg = `Network error reaching ${redactUrl(url)}: ${String((err as Error).message ?? err)}`;\n debug(`✖ network ${msg}`);\n return { ok: false, failure: { kind: 'network', status: null, url, message: msg, cause: err } };\n }\n\n const requestId = response.headers.get(CANARY_REQUEST_ID_HEADER);\n const contentType = response.headers.get('content-type');\n debug(`← ${response.status} ${redactUrl(url)} (ct=${contentType ?? 'n/a'} rid=${requestId ?? 'none'})`);\n\n if (response.ok) {\n return { ok: true, response, requestId };\n }\n\n // Read body once so we can classify and still return something useful.\n // Scrub secrets before constructing user-facing `snippet`; `bodyText` is\n // kept intact for callers that parse structured JSON error bodies.\n const bodyText = await response.clone().text().catch(() => '');\n const snippet = redactSecrets(bodyText.slice(0, 200));\n\n // HTML on a JSON endpoint => proxy block page or captive portal.\n if (looksLikeHtml(bodyText, contentType)) {\n return {\n ok: false,\n failure: {\n kind: 'html-body',\n status: response.status,\n url,\n contentType: contentType ?? undefined,\n requestId,\n body: snippet,\n message: [\n `Got an HTML response from ${url} (status ${response.status}).`,\n 'A corporate proxy block page or captive portal is intercepting this request — the',\n 'response did not come from the Canary API.',\n 'Check that your proxy (e.g. Zscaler) allowlists the API hostname, and that any',\n 'required sign-in to the proxy itself is current.',\n snippet ? `First bytes: ${snippet.replace(/\\s+/g, ' ')}` : '',\n ]\n .filter(Boolean)\n .join('\\n'),\n },\n };\n }\n\n // 401/403 without our header => not our response.\n if ((response.status === 401 || response.status === 403) && !requestId) {\n return {\n ok: false,\n failure: {\n kind: 'proxy-injected-4xx',\n status: response.status,\n url,\n contentType: contentType ?? undefined,\n requestId,\n body: snippet,\n message: [\n `Got ${response.status} from ${url} but the response is missing the \\`${CANARY_REQUEST_ID_HEADER}\\` header.`,\n 'This response was almost certainly injected by a corporate proxy (Zscaler, Netskope,',\n 'Cloudflare Access) rather than returned by our API — retrying \"canary login\" will not fix it.',\n 'Ask your IT team to allowlist the API host, or re-auth to the proxy and try again.',\n ].join('\\n'),\n },\n };\n }\n\n if (response.status === 401) {\n const jwtStatus = jwtExpStatus(token);\n if (jwtStatus === 'valid') {\n return {\n ok: false,\n failure: {\n kind: 'token-revoked',\n status: 401,\n url,\n requestId,\n body: snippet,\n message: [\n 'Server rejected a token that is still valid locally (unexpired JWT).',\n 'Likely causes: the token was revoked, the server\\'s signing key rotated, or the',\n 'user/org was deactivated. `canary login` will issue a fresh token.',\n ].join('\\n'),\n },\n };\n }\n if (jwtStatus === 'expired') {\n return {\n ok: false,\n failure: {\n kind: 'token-expired',\n status: 401,\n url,\n requestId,\n body: snippet,\n message: 'Your stored token has expired. Run: canary login',\n },\n };\n }\n return {\n ok: false,\n failure: {\n kind: 'unauthorized',\n status: 401,\n url,\n requestId,\n body: snippet,\n message: 'Unauthorized. Run: canary login',\n },\n };\n }\n\n return {\n ok: false,\n failure: {\n kind: 'http-error',\n status: response.status,\n url,\n contentType: contentType ?? undefined,\n requestId,\n body: bodyText,\n message: `${response.status} ${response.statusText}${snippet ? `: ${snippet}` : ''}`,\n },\n };\n}\n\n/**\n * Kinds of failure the user can't recover from by retrying the same call —\n * no token on disk, proxy interception, TLS mismatch, rejected JWT. Callers\n * should `exitOnFailure` immediately for these. `http-error` is excluded\n * because the caller often needs to pretty-print a structured error body.\n */\nexport function isTerminalFailure(failure: ClassifiedFailure): boolean {\n return failure.kind !== 'http-error';\n}\n\n/**\n * Print a classified failure and exit(1). Use from command handlers that\n * have no way to recover — matches the historical behavior of the various\n * `if (res.status === 401) { console.error(...); process.exit(1); }` blocks.\n */\nexport function exitOnFailure(failure: ClassifiedFailure): never {\n process.stderr.write(`Error: ${failure.message}\\n`);\n if (isDebug() && failure.body && failure.kind !== 'html-body') {\n process.stderr.write(`[canary-debug] body: ${failure.body}\\n`);\n }\n process.exit(1);\n}\n\n/**\n * Drop-in for `fetch()` in CLI call sites that parse the body themselves:\n * exits the process for terminal failures (TLS/proxy/unauthorized) so the\n * user sees a diagnostic, and returns a Response otherwise — whether 2xx\n * or an HTTP error (so the caller can still inspect .status / .json()).\n */\nexport async function fetchOrExit(\n url: string,\n init: RequestInit & { token?: string; timeoutMs?: number } = {}\n): Promise<Response> {\n const result = await apiFetch(url, init);\n if (result.ok) return result.response;\n if (isTerminalFailure(result.failure)) exitOnFailure(result.failure);\n // http-error: reconstruct a Response the caller can json() / read status on.\n return new Response(result.failure.body ?? '', {\n status: result.failure.status ?? 500,\n headers: result.failure.contentType\n ? { 'content-type': result.failure.contentType }\n : undefined,\n });\n}\n"],"mappings":"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","names":["hasAuthHeader","msg"]}