opencode-anthropic-multi-account 0.2.24 → 0.2.25

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.
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  scrubTemplate
3
- } from "./chunk-RAX4SFCO.js";
3
+ } from "./chunk-3CTML5AX.js";
4
4
 
5
- // src/fingerprint-capture.ts
5
+ // src/claude-code/fingerprint/capture.ts
6
6
  import { spawn } from "child_process";
7
7
  import { createServer } from "http";
8
8
  import { basename, dirname as dirname2, join as join2 } from "path";
@@ -17,11 +17,11 @@ import {
17
17
  writeFile as writeFile2
18
18
  } from "fs/promises";
19
19
 
20
- // src/fingerprint-data.json
21
- var fingerprint_data_default = {
20
+ // src/claude-code/fingerprint/data.json
21
+ var data_default = {
22
22
  _version: 1,
23
23
  _schemaVersion: 1,
24
- _captured: "2026-04-19T12:56:25.330Z",
24
+ _captured: "2026-04-24T13:28:12.469Z",
25
25
  _source: "bundled",
26
26
  agent_identity: "You are a Claude agent, built on Anthropic's Claude Agent SDK.",
27
27
  system_prompt: `You are an interactive agent that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
@@ -93,6 +93,8 @@ In code: default to writing no comments. Never write multi-paragraph docstrings
93
93
  - Use the Agent tool with specialized agents when the task at hand matches the agent's description. Subagents are valuable for parallelizing independent queries or for protecting the main context window from excessive results, but they should not be used excessively when not needed. Importantly, avoid duplicating work that subagents are already doing - if you delegate research to a subagent, do not also perform the same searches yourself.
94
94
  - For broad codebase exploration or research that'll take more than 3 queries, spawn Agent with subagent_type=Explore. Otherwise use the Glob or Grep directly.
95
95
  - When the user types \`/<skill-name>\`, invoke it via Skill. Only use skills listed in the user-invocable skills section \u2014 don't guess.
96
+ - When work you just finished has a natural future follow-up, end your reply with a one-line offer to \`/schedule\` a background agent to do it \u2014 name the concrete action and cadence ("Want me to /schedule an agent in 2 weeks to open a cleanup PR for the flag?"). One-time signals: a feature flag/gate/experiment/staged rollout (clean it up or ramp it), a soak window or metric to verify (query it and post results), a long-running job with an ETA (check status and report), a temp workaround/instrumentation/.skip left in (open a removal PR), a "remove once X" TODO. Recurring signals: a sweep/triage/report/queue-drain the user just did by hand, or anything "weekly"/"again"/"piling up" \u2014 offer to run it as a routine. The bar is 70%+ odds the user says yes \u2014 skip it for refactors, bug fixes with tests, docs, renames, routine dep bumps, plain feature merges, or when the user signals closure ("nothing else to do", "should be fine now"). Don't stack offers on back-to-back turns; let most tasks just be tasks.
97
+ - If the user asks about "ultrareview" or how to run it, explain that /ultrareview launches a multi-agent cloud review of the current branch (or /ultrareview <PR#> for a GitHub PR). It is user-triggered and billed; you cannot launch it yourself, so do not attempt to via Bash or otherwise. It needs a git repository (offer to "git init" if not in one); the no-arg form bundles the local branch and does not need a GitHub remote.
96
98
 
97
99
  # Language
98
100
  Always respond in Korean. Use Korean for all explanations, comments, and communications with the user. Technical terms and code identifiers should remain in their original form.
@@ -100,8 +102,6 @@ Maintain full orthographic correctness for Korean, including all required diacri
100
102
 
101
103
  When working with tool results, write down any important information you might need later in your response, as the original tool result may be cleared later.
102
104
 
103
- Length limits: keep text between tool calls to \u226425 words. Keep final responses to \u2264100 words unless the task requires more detail.
104
-
105
105
  gitStatus: This is the git status at the start of the conversation. Note that this status is a snapshot in time, and will not update during the conversation.
106
106
 
107
107
  Current branch: main
@@ -779,7 +779,7 @@ Ensure your plan is complete and unambiguous:
779
779
  },
780
780
  {
781
781
  name: "Monitor",
782
- description: 'Start a background monitor that streams events from a long-running script. Each stdout line is an event \u2014 you keep working and notifications arrive in the chat. Events arrive on their own schedule and are not replies from the user, even if one lands while you\'re waiting for the user to answer a question.\n\nMonitor is for the **streaming** case: "tell me every time X happens." For one-shot "wait until X is done," use Bash with run_in_background instead \u2014 you\'ll get a completion notification when it exits.\n\nYour script\'s stdout is the event stream. Each line becomes a notification. Exit ends the watch.\n\n # Each matching log line is an event\n tail -f /var/log/app.log | grep --line-buffered "ERROR"\n\n # Each file change is an event\n inotifywait -m --format \'%e %f\' /watched/dir\n\n # Poll GitHub for new PR comments and emit one line per new comment\n last=$(date -u +%Y-%m-%dT%H:%M:%SZ)\n while true; do\n now=$(date -u +%Y-%m-%dT%H:%M:%SZ)\n gh api "repos/owner/repo/issues/123/comments?since=$last" --jq \'.[] | "\\(.user.login): \\(.body)"\'\n last=$now; sleep 30\n done\n\n # Node script that emits events as they arrive (e.g. WebSocket listener)\n node watch-for-events.js\n\n**Script quality:**\n- Always use `grep --line-buffered` in pipes \u2014 without it, pipe buffering delays events by minutes.\n- In poll loops, handle transient failures (`curl ... || true`) \u2014 one failed request shouldn\'t kill the monitor.\n- Poll intervals: 30s+ for remote APIs (rate limits), 0.5-1s for local checks.\n- Write a specific `description` \u2014 it appears in every notification ("errors in deploy.log" not "watching logs").\n- Only stdout is the event stream. Stderr goes to the output file (readable via Read) but does not trigger notifications \u2014 for a command you run directly (e.g. `python train.py 2>&1 | grep --line-buffered ...`), merge stderr with `2>&1` so its failures reach your filter. (No effect on `tail -f` of an existing log \u2014 that file only contains what its writer redirected.)\n\n**Coverage \u2014 silence is not success.** When watching a job or process for an outcome, your filter must match every terminal state, not just the happy path. A monitor that greps only for the success marker stays silent through a crashloop, a hung process, or an unexpected exit \u2014 and silence looks identical to "still running." Before arming, ask: *if this process crashed right now, would my filter emit anything?* If not, widen it.\n\n # Wrong \u2014 silent on crash, hang, or any non-success exit\n tail -f run.log | grep --line-buffered "elapsed_steps="\n\n # Right \u2014 one alternation covering progress + the failure signatures you\'d act on\n tail -f run.log | grep -E --line-buffered "elapsed_steps=|Traceback|Error|FAILED|assert|Killed|OOM"\n\nFor poll loops checking job state, emit on every terminal status (`succeeded|failed|cancelled|timeout`), not just success. If you cannot confidently enumerate the failure signatures, broaden the grep alternation rather than narrow it \u2014 some extra noise is better than missing a crashloop.\n\n**Output volume**: Every stdout line is a conversation message, so the filter should be selective \u2014 but selective means "the lines you\'d act on," not "only good news." Never pipe raw logs; use `grep --line-buffered`, `awk`, or a wrapper that emits exactly the success and failure signals you care about. Monitors that produce too many events are automatically stopped; restart with a tighter filter if this happens.\n\nStdout lines within 200ms are batched into a single notification, so multiline output from a single event groups naturally.\n\nThe script runs in the same shell environment as Bash. Exit ends the watch (exit code is reported). Timeout \u2192 killed. Set `persistent: true` for session-length watches (PR monitoring, log tails) \u2014 the monitor runs until you call TaskStop or the session ends. Use TaskStop to cancel early.',
782
+ description: 'Start a background monitor that streams events from a long-running script. Each stdout line is an event \u2014 you keep working and notifications arrive in the chat. Events arrive on their own schedule and are not replies from the user, even if one lands while you\'re waiting for the user to answer a question.\n\nPick by how many notifications you need:\n- **One** ("tell me when the server is ready / the build finishes") \u2192 use **Bash with `run_in_background`** and a command that exits when the condition is true, e.g. `until grep -q "Ready in" dev.log; do sleep 0.5; done`. You get a single completion notification when it exits.\n- **One per occurrence, indefinitely** ("tell me every time an ERROR line appears") \u2192 Monitor with an unbounded command (`tail -f`, `inotifywait -m`, `while true`).\n- **One per occurrence, until a known end** ("emit each CI step result, stop when the run completes") \u2192 Monitor with a command that emits lines and then exits.\n\nYour script\'s stdout is the event stream. Each line becomes a notification. Exit ends the watch.\n\n # Each matching log line is an event\n tail -f /var/log/app.log | grep --line-buffered "ERROR"\n\n # Each file change is an event\n inotifywait -m --format \'%e %f\' /watched/dir\n\n # Poll GitHub for new PR comments and emit one line per new comment\n last=$(date -u +%Y-%m-%dT%H:%M:%SZ)\n while true; do\n now=$(date -u +%Y-%m-%dT%H:%M:%SZ)\n gh api "repos/owner/repo/issues/123/comments?since=$last" --jq \'.[] | "\\(.user.login): \\(.body)"\'\n last=$now; sleep 30\n done\n\n # Node script that emits events as they arrive (e.g. WebSocket listener)\n node watch-for-events.js\n\n # Per-occurrence with a natural end: emit each CI check as it lands, exit when the run completes\n prev=""\n while true; do\n s=$(gh pr checks 123 --json name,bucket)\n cur=$(jq -r \'.[] | select(.bucket!="pending") | "\\(.name): \\(.bucket)"\' <<<"$s" | sort)\n comm -13 <(echo "$prev") <(echo "$cur")\n prev=$cur\n jq -e \'all(.bucket!="pending")\' <<<"$s" >/dev/null && break\n sleep 30\n done\n\n**Don\'t use an unbounded command for a single notification.** `tail -f`, `inotifywait -m`, and `while true` never exit on their own, so the monitor stays armed until timeout even after the event has fired. For "tell me when X is ready," use Bash `run_in_background` with an `until` loop instead (one notification, ends in seconds). Note that `tail -f log | grep -m 1 ...` does *not* fix this: if the log goes quiet after the match, `tail` never receives SIGPIPE and the pipeline hangs anyway.\n\n**Script quality:**\n- Always use `grep --line-buffered` in pipes \u2014 without it, pipe buffering delays events by minutes.\n- In poll loops, handle transient failures (`curl ... || true`) \u2014 one failed request shouldn\'t kill the monitor.\n- Poll intervals: 30s+ for remote APIs (rate limits), 0.5-1s for local checks.\n- Write a specific `description` \u2014 it appears in every notification ("errors in deploy.log" not "watching logs").\n- Only stdout is the event stream. Stderr goes to the output file (readable via Read) but does not trigger notifications \u2014 for a command you run directly (e.g. `python train.py 2>&1 | grep --line-buffered ...`), merge stderr with `2>&1` so its failures reach your filter. (No effect on `tail -f` of an existing log \u2014 that file only contains what its writer redirected.)\n\n**Coverage \u2014 silence is not success.** When watching a job or process for an outcome, your filter must match every terminal state, not just the happy path. A monitor that greps only for the success marker stays silent through a crashloop, a hung process, or an unexpected exit \u2014 and silence looks identical to "still running." Before arming, ask: *if this process crashed right now, would my filter emit anything?* If not, widen it.\n\n # Wrong \u2014 silent on crash, hang, or any non-success exit\n tail -f run.log | grep --line-buffered "elapsed_steps="\n\n # Right \u2014 one alternation covering progress + the failure signatures you\'d act on\n tail -f run.log | grep -E --line-buffered "elapsed_steps=|Traceback|Error|FAILED|assert|Killed|OOM"\n\nFor poll loops checking job state, emit on every terminal status (`succeeded|failed|cancelled|timeout`), not just success. If you cannot confidently enumerate the failure signatures, broaden the grep alternation rather than narrow it \u2014 some extra noise is better than missing a crashloop.\n\n**Output volume**: Every stdout line is a conversation message, so the filter should be selective \u2014 but selective means "the lines you\'d act on," not "only good news." Never pipe raw logs; use `grep --line-buffered`, `awk`, or a wrapper that emits exactly the success and failure signals you care about. Monitors that produce too many events are automatically stopped; restart with a tighter filter if this happens.\n\nStdout lines within 200ms are batched into a single notification, so multiline output from a single event groups naturally.\n\nThe script runs in the same shell environment as Bash. Exit ends the watch (exit code is reported). Timeout \u2192 killed. Set `persistent: true` for session-length watches (PR monitoring, log tails) \u2014 the monitor runs until you call TaskStop or the session ends. Use TaskStop to cancel early.',
783
783
  input_schema: {
784
784
  $schema: "https://json-schema.org/draft/2020-12/schema",
785
785
  type: "object",
@@ -889,7 +889,7 @@ If the result says the push wasn't sent, that's expected \u2014 no action needed
889
889
  },
890
890
  {
891
891
  name: "Read",
892
- description: 'Reads a file from the local filesystem. You can access any file directly by using this tool.\nAssume this tool is able to read all files on the machine. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned.\n\nUsage:\n- The file_path parameter must be an absolute path, not a relative path\n- By default, it reads up to 2000 lines starting from the beginning of the file\n- When you already know which part of the file you need, only read that part. This can be important for larger files.\n- Results are returned using cat -n format, with line numbers starting at 1\n- This tool allows Claude Code to read images (eg PNG, JPG, etc). When reading an image file the contents are presented visually as Claude Code is a multimodal LLM.\n- This tool can read PDF files (.pdf). For large PDFs (more than 10 pages), you MUST provide the pages parameter to read specific page ranges (e.g., pages: "1-5"). Reading a large PDF without the pages parameter will fail. Maximum 20 pages per request.\n- This tool can read Jupyter notebooks (.ipynb files) and returns all cells with their outputs, combining code, text, and visualizations.\n- This tool can only read files, not directories. To read a directory, use an ls command via the Bash tool.\n- You will regularly be asked to read screenshots. If the user provides a path to a screenshot, ALWAYS use this tool to view the file at the path. This tool will work with all temporary file paths.\n- If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents.\n- Do NOT re-read a file you just edited to verify \u2014 Edit/Write would have errored if the change failed, and the harness tracks file state for you.',
892
+ description: 'Reads a file from the local filesystem. You can access any file directly by using this tool.\nAssume this tool is able to read all files on the machine. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned.\n\nUsage:\n- The file_path parameter must be an absolute path, not a relative path\n- By default, it reads up to 2000 lines starting from the beginning of the file\n- When you already know which part of the file you need, only read that part. This can be important for larger files.\n- Results are returned using cat -n format, with line numbers starting at 1\n- This tool allows Claude Code to read images (eg PNG, JPG, etc). When reading an image file the contents are presented visually as Claude Code is a multimodal LLM.\n- This tool can read PDF files (.pdf). For large PDFs (more than 10 pages), you MUST provide the pages parameter to read specific page ranges (e.g., pages: "1-5"). Reading a large PDF without the pages parameter will fail. Maximum 20 pages per request.\n- This tool can read Jupyter notebooks (.ipynb files) and returns all cells with their outputs, combining code, text, and visualizations.\n- This tool can only read files, not directories. To list files in a directory, use the registered shell tool.\n- You will regularly be asked to read screenshots. If the user provides a path to a screenshot, ALWAYS use this tool to view the file at the path. This tool will work with all temporary file paths.\n- If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents.',
893
893
  input_schema: {
894
894
  $schema: "https://json-schema.org/draft/2020-12/schema",
895
895
  type: "object",
@@ -1417,8 +1417,8 @@ IMPORTANT - Use the correct year in search queries:
1417
1417
  "WebSearch",
1418
1418
  "Write"
1419
1419
  ],
1420
- anthropic_beta: "claude-code-20250219,oauth-2025-04-20,context-1m-2025-08-07,interleaved-thinking-2025-05-14,context-management-2025-06-27,prompt-caching-scope-2026-01-05,advisor-tool-2026-03-01,effort-2025-11-24",
1421
- cc_version: "2.1.114",
1420
+ anthropic_beta: "claude-code-20250219,interleaved-thinking-2025-05-14,context-management-2025-06-27,prompt-caching-scope-2026-01-05,advisor-tool-2026-03-01,effort-2025-11-24,afk-mode-2026-01-31",
1421
+ cc_version: "2.1.119",
1422
1422
  header_order: [
1423
1423
  "Accept",
1424
1424
  "Authorization",
@@ -1444,11 +1444,11 @@ IMPORTANT - Use the correct year in search queries:
1444
1444
  ],
1445
1445
  header_values: {
1446
1446
  accept: "application/json",
1447
- "anthropic-beta": "claude-code-20250219,oauth-2025-04-20,context-1m-2025-08-07,interleaved-thinking-2025-05-14,context-management-2025-06-27,prompt-caching-scope-2026-01-05,advisor-tool-2026-03-01,effort-2025-11-24",
1447
+ "anthropic-beta": "claude-code-20250219,interleaved-thinking-2025-05-14,context-management-2025-06-27,prompt-caching-scope-2026-01-05,advisor-tool-2026-03-01,effort-2025-11-24,afk-mode-2026-01-31",
1448
1448
  "anthropic-dangerous-direct-browser-access": "true",
1449
1449
  "anthropic-version": "2023-06-01",
1450
1450
  "content-type": "application/json",
1451
- "user-agent": "claude-cli/2.1.114 (external, sdk-cli)",
1451
+ "user-agent": "claude-cli/2.1.119 (external, sdk-cli)",
1452
1452
  "x-app": "cli",
1453
1453
  "x-stainless-timeout": "600"
1454
1454
  },
@@ -1466,15 +1466,22 @@ IMPORTANT - Use the correct year in search queries:
1466
1466
  ]
1467
1467
  };
1468
1468
 
1469
- // src/cli-version.ts
1470
- import { execFileSync } from "child_process";
1471
- var DEFAULT_CLI_VERSION = "2.1.100";
1469
+ // src/claude-code/cli-version.ts
1470
+ import { execFileSync as defaultExecFileSync } from "child_process";
1471
+ var DEFAULT_CLI_VERSION = data_default.cc_version;
1472
1472
  var CLI_VERSION_PATTERN = /(\d+\.\d+\.\d+)/;
1473
1473
  var CLAUDE_VERSION_TIMEOUT_MS = 3e3;
1474
1474
  var detectedVersion = null;
1475
+ var cliVersionProbe = defaultExecFileSync;
1475
1476
  function parseCliVersion(output) {
1476
1477
  return output.match(CLI_VERSION_PATTERN)?.[1] ?? null;
1477
1478
  }
1479
+ function probeCliVersion() {
1480
+ return cliVersionProbe("claude", ["--version"], {
1481
+ encoding: "utf8",
1482
+ timeout: CLAUDE_VERSION_TIMEOUT_MS
1483
+ });
1484
+ }
1478
1485
  function detectCliVersion() {
1479
1486
  if (detectedVersion !== null) {
1480
1487
  return detectedVersion;
@@ -1485,10 +1492,7 @@ function detectCliVersion() {
1485
1492
  return detectedVersion;
1486
1493
  }
1487
1494
  try {
1488
- const output = execFileSync("claude", ["--version"], {
1489
- encoding: "utf8",
1490
- timeout: CLAUDE_VERSION_TIMEOUT_MS
1491
- });
1495
+ const output = probeCliVersion();
1492
1496
  detectedVersion = parseCliVersion(output) ?? DEFAULT_CLI_VERSION;
1493
1497
  } catch {
1494
1498
  detectedVersion = DEFAULT_CLI_VERSION;
@@ -1496,8 +1500,9 @@ function detectCliVersion() {
1496
1500
  return detectedVersion;
1497
1501
  }
1498
1502
 
1499
- // src/oauth-config-detect.ts
1503
+ // src/claude-code/oauth-config/detect.ts
1500
1504
  import { createHash } from "crypto";
1505
+ import { execFileSync as defaultExecFileSync2 } from "child_process";
1501
1506
  import { existsSync } from "fs";
1502
1507
  import { mkdir, readFile, writeFile } from "fs/promises";
1503
1508
  import { homedir, platform } from "os";
@@ -1513,14 +1518,14 @@ var cc_derived_defaults_default = {
1513
1518
  },
1514
1519
  oauth: {
1515
1520
  clientId: "9d1c250a-e61b-44d9-88ed-5944d1962f5e",
1516
- authorizeUrl: "https://claude.com/cai/oauth/authorize",
1521
+ authorizeUrl: "https://claude.ai/oauth/authorize",
1517
1522
  tokenUrl: "https://platform.claude.com/v1/oauth/token",
1518
- scopes: "user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload",
1523
+ scopes: "org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload",
1519
1524
  baseApiUrl: "https://api.anthropic.com"
1520
1525
  }
1521
1526
  };
1522
1527
 
1523
- // src/utils.ts
1528
+ // src/shared/utils.ts
1524
1529
  import {
1525
1530
  createMinimalClient,
1526
1531
  formatWaitTime,
@@ -1530,7 +1535,7 @@ import {
1530
1535
  sleep
1531
1536
  } from "opencode-multi-account-core";
1532
1537
 
1533
- // src/constants.ts
1538
+ // src/shared/constants.ts
1534
1539
  import { anthropicOAuthAdapter } from "opencode-multi-account-core";
1535
1540
  var ANTHROPIC_OAUTH_ADAPTER = anthropicOAuthAdapter;
1536
1541
  var ANTHROPIC_CLIENT_ID = ANTHROPIC_OAUTH_ADAPTER.oauthClientId;
@@ -1543,14 +1548,14 @@ var PLAN_LABELS = ANTHROPIC_OAUTH_ADAPTER.planLabels;
1543
1548
  var TOKEN_EXPIRY_BUFFER_MS = 6e4;
1544
1549
  var TOKEN_REFRESH_TIMEOUT_MS = 3e4;
1545
1550
 
1546
- // src/config.ts
1551
+ // src/shared/config.ts
1547
1552
  import {
1548
1553
  createConfigLoader
1549
1554
  } from "opencode-multi-account-core";
1550
1555
  var configLoader = createConfigLoader("claude-multiauth.json");
1551
1556
  var { getConfig, loadConfig, resetConfigCache, updateConfigField } = configLoader;
1552
1557
 
1553
- // src/utils.ts
1558
+ // src/shared/utils.ts
1554
1559
  async function showToast(client, message, variant) {
1555
1560
  if (getConfig().quiet_mode) return;
1556
1561
  try {
@@ -1566,28 +1571,57 @@ function debugLog(client, message, extra) {
1566
1571
  });
1567
1572
  }
1568
1573
 
1569
- // src/oauth-config-detect.ts
1574
+ // src/claude-code/oauth-config/detect.ts
1570
1575
  var CONFIG_SCAN_WINDOW_CHARS = 4096;
1571
1576
  var CONFIG_SCAN_LOOKBACK_CHARS = 512;
1572
- var REJECTED_SCOPE = ["org", "create_api_key"].join(":");
1573
- var SAFE_FALLBACK_SCOPES = "user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload";
1577
+ var KNOWN_PROD_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
1578
+ var POLLUTED_CACHED_SCOPE = "https://www.googleapis.com/auth/cloud-platform";
1579
+ var SAFE_FALLBACK_SCOPES = "org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload";
1574
1580
  var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
1575
1581
  var CACHE_FILE_NAME = "anthropic-oauth-config-cache.json";
1576
1582
  var DEFAULT_OVERRIDE_FILE_NAME = "oauth-config.override.json";
1577
1583
  var derivedDefaults = cc_derived_defaults_default;
1578
- var FALLBACK = {
1579
- clientId: derivedDefaults.oauth?.clientId || "9d1c250a-e61b-44d9-88ed-5944d1962f5e",
1580
- authorizeUrl: derivedDefaults.oauth?.authorizeUrl || "https://claude.com/cai/oauth/authorize",
1584
+ var fallbackPayload = normalizeDetectedOAuthConfigPayload({
1585
+ clientId: derivedDefaults.oauth?.clientId || KNOWN_PROD_CLIENT_ID,
1586
+ authorizeUrl: derivedDefaults.oauth?.authorizeUrl || "https://claude.ai/oauth/authorize",
1581
1587
  tokenUrl: derivedDefaults.oauth?.tokenUrl || "https://platform.claude.com/v1/oauth/token",
1582
- scopes: sanitizeScopes(derivedDefaults.oauth?.scopes),
1583
- baseApiUrl: derivedDefaults.oauth?.baseApiUrl || "https://api.anthropic.com",
1588
+ scopes: derivedDefaults.oauth?.scopes || SAFE_FALLBACK_SCOPES,
1589
+ baseApiUrl: derivedDefaults.oauth?.baseApiUrl || "https://api.anthropic.com"
1590
+ });
1591
+ var FALLBACK = {
1592
+ ...fallbackPayload,
1584
1593
  source: "fallback"
1585
1594
  };
1586
- function sanitizeScopes(scopes) {
1587
- if (!scopes || scopes.includes(REJECTED_SCOPE)) {
1588
- return SAFE_FALLBACK_SCOPES;
1595
+ function hasPollutedCachedScope(scopes) {
1596
+ const parsedScopes = scopes.split(/\s+/).filter(Boolean);
1597
+ return parsedScopes.includes(POLLUTED_CACHED_SCOPE) || !parsedScopes.includes("org:create_api_key");
1598
+ }
1599
+ function filterScopesByBinaryPresence(buf, expected) {
1600
+ const verified = [];
1601
+ for (const scope of expected) {
1602
+ const needle = Buffer.from(`"${scope}"`);
1603
+ if (buf.includes(needle)) {
1604
+ verified.push(scope);
1605
+ }
1606
+ }
1607
+ return verified;
1608
+ }
1609
+ function getVerifiedCanonicalScopes(buf, fallbackScopes) {
1610
+ const expectedScopes = fallbackScopes.split(/\s+/).filter(Boolean);
1611
+ const verifiedScopes = filterScopesByBinaryPresence(buf, expectedScopes);
1612
+ return verifiedScopes.length === expectedScopes.length ? verifiedScopes.join(" ") : null;
1613
+ }
1614
+ function normalizeAuthorizeUrl(url) {
1615
+ if (url === "https://claude.com/cai/oauth/authorize") {
1616
+ return "https://claude.ai/oauth/authorize";
1589
1617
  }
1590
- return scopes;
1618
+ return url;
1619
+ }
1620
+ function normalizeDetectedOAuthConfigPayload(payload) {
1621
+ return {
1622
+ ...payload,
1623
+ authorizeUrl: normalizeAuthorizeUrl(payload.authorizeUrl)
1624
+ };
1591
1625
  }
1592
1626
  function pickNearestScopes(block, centerIndex) {
1593
1627
  return pickNearestValue(block, centerIndex, /SCOPES\s*:\s*"([^"]+)"/gi) || pickNearestValue(block, centerIndex, /scope[s]?\s*:\s*"([^"]+)"/gi) || null;
@@ -1611,10 +1645,12 @@ function extractCandidateBlocks(binaryText) {
1611
1645
  const currentIndex = currentMatch.index ?? 0;
1612
1646
  const previousClientIdIndex = clientIdMatches[index - 1]?.index;
1613
1647
  const nextClientIdIndex = clientIdMatches[index + 1]?.index;
1614
- const leftBoundary = previousClientIdIndex === void 0 ? Math.max(0, currentIndex - CONFIG_SCAN_LOOKBACK_CHARS) : Math.floor((previousClientIdIndex + currentIndex) / 2);
1615
- const rightBoundary = nextClientIdIndex === void 0 ? Math.min(binaryText.length, currentIndex + CONFIG_SCAN_WINDOW_CHARS) : Math.floor((currentIndex + nextClientIdIndex) / 2);
1616
- const start = Math.max(0, leftBoundary);
1617
- const end = Math.min(binaryText.length, Math.max(currentIndex + 1, rightBoundary));
1648
+ const { start, end } = getCandidateBlockRange(
1649
+ currentIndex,
1650
+ previousClientIdIndex,
1651
+ nextClientIdIndex,
1652
+ binaryText.length
1653
+ );
1618
1654
  const key = `${start}:${end}`;
1619
1655
  if (seenRanges.has(key)) {
1620
1656
  continue;
@@ -1627,6 +1663,19 @@ function extractCandidateBlocks(binaryText) {
1627
1663
  }
1628
1664
  return blocks;
1629
1665
  }
1666
+ function midpoint(left, right) {
1667
+ return Math.floor((left + right) / 2);
1668
+ }
1669
+ function getCandidateBlockRange(currentIndex, previousClientIdIndex, nextClientIdIndex, textLength) {
1670
+ const boundedLeftEdge = currentIndex - CONFIG_SCAN_LOOKBACK_CHARS;
1671
+ const boundedRightEdge = currentIndex + CONFIG_SCAN_WINDOW_CHARS;
1672
+ const leftBoundary = previousClientIdIndex === void 0 ? boundedLeftEdge : Math.max(boundedLeftEdge, midpoint(previousClientIdIndex, currentIndex));
1673
+ const rightBoundary = nextClientIdIndex === void 0 ? boundedRightEdge : Math.min(boundedRightEdge, midpoint(currentIndex, nextClientIdIndex));
1674
+ return {
1675
+ start: Math.max(0, leftBoundary),
1676
+ end: Math.min(textLength, Math.max(currentIndex + 1, rightBoundary))
1677
+ };
1678
+ }
1630
1679
  function pickNearestValue(block, centerIndex, pattern) {
1631
1680
  let nearestValue;
1632
1681
  let nearestDistance = Number.POSITIVE_INFINITY;
@@ -1665,7 +1714,7 @@ function extractCandidateFromBlock(block) {
1665
1714
  clientId: clientIdMatch[1],
1666
1715
  authorizeUrl: authorizeUrl || FALLBACK.authorizeUrl,
1667
1716
  tokenUrl: tokenUrl || FALLBACK.tokenUrl,
1668
- scopes: sanitizeScopes(extractedScopes),
1717
+ scopes: extractedScopes || FALLBACK.scopes,
1669
1718
  baseApiUrl: baseApiUrl || FALLBACK.baseApiUrl
1670
1719
  };
1671
1720
  if (!isDetectedOAuthConfigPayload(payload)) {
@@ -1678,9 +1727,15 @@ function extractCandidateFromBlock(block) {
1678
1727
  }
1679
1728
  var memoizedConfig = null;
1680
1729
  var detectorTestOverrides = {};
1730
+ function getPlatform() {
1731
+ return detectorTestOverrides.platform?.() ?? platform();
1732
+ }
1733
+ function fileExists(path) {
1734
+ return (detectorTestOverrides.existsSync ?? existsSync)(path);
1735
+ }
1681
1736
  function candidatePaths() {
1682
1737
  const home = homedir();
1683
- if (platform() === "win32") {
1738
+ if (getPlatform() === "win32") {
1684
1739
  return [
1685
1740
  join(home, ".local", "bin", "claude.exe"),
1686
1741
  join(home, "AppData", "Roaming", "npm", "node_modules", "@anthropic-ai", "claude-code", "cli.js"),
@@ -1700,6 +1755,49 @@ function candidatePaths() {
1700
1755
  join(home, ".claude", "local", "node_modules", "@anthropic-ai", "claude-code", "cli.mjs")
1701
1756
  ];
1702
1757
  }
1758
+ function enumerateCCCandidates() {
1759
+ const seen = /* @__PURE__ */ new Set();
1760
+ const candidates = [];
1761
+ const currentPlatform = getPlatform();
1762
+ const pathDelimiter = currentPlatform === "win32" ? ";" : ":";
1763
+ const pathDirs = (detectorTestOverrides.pathEnv ?? process.env.PATH ?? "").split(pathDelimiter).filter(Boolean);
1764
+ const pathCandidateNames = currentPlatform === "win32" ? ["claude.exe", "claude.cmd", "claude"] : ["claude"];
1765
+ const addCandidate = (candidatePath) => {
1766
+ const key = currentPlatform === "win32" ? candidatePath.toLowerCase() : candidatePath;
1767
+ if (seen.has(key) || !fileExists(candidatePath)) {
1768
+ return;
1769
+ }
1770
+ seen.add(key);
1771
+ candidates.push(candidatePath);
1772
+ };
1773
+ for (const dir of pathDirs) {
1774
+ for (const fileName of pathCandidateNames) {
1775
+ addCandidate(join(dir, fileName));
1776
+ }
1777
+ }
1778
+ for (const candidatePath of candidatePaths()) {
1779
+ addCandidate(candidatePath);
1780
+ }
1781
+ return candidates;
1782
+ }
1783
+ function probeOneVersion(binPath) {
1784
+ const currentPlatform = getPlatform();
1785
+ if (currentPlatform === "win32" && /\.(cmd|bat)$/i.test(binPath) && /[&|><^"'%\r\n`$;(){}\[\]]/.test(binPath)) {
1786
+ return null;
1787
+ }
1788
+ try {
1789
+ const output = (detectorTestOverrides.execFileSync ?? defaultExecFileSync2)(binPath, ["--version"], {
1790
+ timeout: 2e3,
1791
+ encoding: "utf-8",
1792
+ windowsHide: true,
1793
+ stdio: ["ignore", "pipe", "ignore"],
1794
+ shell: currentPlatform === "win32" && /\.(cmd|bat)$/i.test(binPath)
1795
+ });
1796
+ return output.match(/(\d+\.\d+\.\d+(?:[.\-][\w.\-]+)?)/)?.[1] ?? null;
1797
+ } catch {
1798
+ return null;
1799
+ }
1800
+ }
1703
1801
  function getCachePath() {
1704
1802
  return join(getConfigDir(), CACHE_FILE_NAME);
1705
1803
  }
@@ -1721,13 +1819,17 @@ function isDetectedOAuthConfigPayload(value) {
1721
1819
  const candidate = value;
1722
1820
  return typeof candidate.clientId === "string" && UUID_PATTERN.test(candidate.clientId) && typeof candidate.authorizeUrl === "string" && isValidUrl(candidate.authorizeUrl) && typeof candidate.tokenUrl === "string" && isValidUrl(candidate.tokenUrl) && typeof candidate.scopes === "string" && candidate.scopes.length > 0;
1723
1821
  }
1724
- function toFallbackConfig(ccPath, ccHash) {
1822
+ function buildResolvedConfig(payload, source, ccPath, ccHash) {
1725
1823
  return {
1726
- ...FALLBACK,
1824
+ ...payload,
1825
+ source,
1727
1826
  ...ccPath ? { ccPath } : {},
1728
1827
  ...ccHash ? { ccHash } : {}
1729
1828
  };
1730
1829
  }
1830
+ function toFallbackConfig(ccPath, ccHash) {
1831
+ return buildResolvedConfig(FALLBACK, "fallback", ccPath, ccHash);
1832
+ }
1731
1833
  function isOverrideDisabled() {
1732
1834
  return process.env.ANTHROPIC_MULTI_ACCOUNT_OAUTH_DISABLE_OVERRIDE === "1";
1733
1835
  }
@@ -1741,30 +1843,44 @@ function readOverrideString(value) {
1741
1843
  function getOverridePath() {
1742
1844
  return readOverrideString(process.env.ANTHROPIC_MULTI_ACCOUNT_OAUTH_OVERRIDE_PATH) ?? getDefaultOverridePath();
1743
1845
  }
1744
- function normalizeOverride(value) {
1846
+ function readOverrideRecord(value) {
1745
1847
  if (typeof value !== "object" || value === null) {
1848
+ return null;
1849
+ }
1850
+ return value;
1851
+ }
1852
+ function readOverrideField(candidate, key) {
1853
+ const value = candidate[key];
1854
+ return typeof value === "string" ? readOverrideString(value) : void 0;
1855
+ }
1856
+ function readOverrideUrl(candidate, key) {
1857
+ const value = readOverrideField(candidate, key);
1858
+ return value && isValidUrl(value) ? value : void 0;
1859
+ }
1860
+ function normalizeOverride(value) {
1861
+ const candidate = readOverrideRecord(value);
1862
+ if (!candidate) {
1746
1863
  return {};
1747
1864
  }
1748
- const candidate = value;
1749
1865
  const normalized = {};
1750
- const clientId = readOverrideString(typeof candidate.clientId === "string" ? candidate.clientId : void 0);
1866
+ const clientId = readOverrideField(candidate, "clientId");
1751
1867
  if (clientId && UUID_PATTERN.test(clientId)) {
1752
1868
  normalized.clientId = clientId;
1753
1869
  }
1754
- const authorizeUrl = readOverrideString(typeof candidate.authorizeUrl === "string" ? candidate.authorizeUrl : void 0);
1755
- if (authorizeUrl && isValidUrl(authorizeUrl)) {
1756
- normalized.authorizeUrl = authorizeUrl;
1870
+ const authorizeUrl = readOverrideUrl(candidate, "authorizeUrl");
1871
+ if (authorizeUrl) {
1872
+ normalized.authorizeUrl = normalizeAuthorizeUrl(authorizeUrl);
1757
1873
  }
1758
- const tokenUrl = readOverrideString(typeof candidate.tokenUrl === "string" ? candidate.tokenUrl : void 0);
1759
- if (tokenUrl && isValidUrl(tokenUrl)) {
1874
+ const tokenUrl = readOverrideUrl(candidate, "tokenUrl");
1875
+ if (tokenUrl) {
1760
1876
  normalized.tokenUrl = tokenUrl;
1761
1877
  }
1762
- const scopes = readOverrideString(typeof candidate.scopes === "string" ? candidate.scopes : void 0);
1878
+ const scopes = readOverrideField(candidate, "scopes");
1763
1879
  if (scopes) {
1764
- normalized.scopes = sanitizeScopes(scopes);
1880
+ normalized.scopes = scopes;
1765
1881
  }
1766
- const baseApiUrl = readOverrideString(typeof candidate.baseApiUrl === "string" ? candidate.baseApiUrl : void 0);
1767
- if (baseApiUrl && isValidUrl(baseApiUrl)) {
1882
+ const baseApiUrl = readOverrideUrl(candidate, "baseApiUrl");
1883
+ if (baseApiUrl) {
1768
1884
  normalized.baseApiUrl = baseApiUrl;
1769
1885
  }
1770
1886
  return normalized;
@@ -1801,16 +1917,22 @@ async function applyManualOverride(baseConfig) {
1801
1917
  };
1802
1918
  }
1803
1919
  function findCCBinary() {
1804
- const override = process.env.DARIO_CC_PATH;
1805
- if (override && existsSync(override)) {
1920
+ const override = process.env.ANTHROPIC_CC_PATH;
1921
+ if (override && fileExists(override)) {
1806
1922
  return override;
1807
1923
  }
1808
- for (const candidatePath of candidatePaths()) {
1809
- if (existsSync(candidatePath)) {
1810
- return candidatePath;
1811
- }
1924
+ const candidates = enumerateCCCandidates();
1925
+ if (candidates.length === 0) {
1926
+ return null;
1812
1927
  }
1813
- return null;
1928
+ if (candidates.length === 1) {
1929
+ return candidates[0] ?? null;
1930
+ }
1931
+ const probedCandidates = candidates.map((candidatePath) => {
1932
+ const version = probeOneVersion(candidatePath);
1933
+ return version ? { path: candidatePath, version } : null;
1934
+ }).filter((candidate) => candidate !== null).sort((left, right) => compareVersions(right.version, left.version) ?? 0);
1935
+ return probedCandidates[0]?.path ?? candidates[0] ?? null;
1814
1936
  }
1815
1937
  async function fingerprintBinary(path) {
1816
1938
  const binaryContents = await readFile(path);
@@ -1819,19 +1941,24 @@ async function fingerprintBinary(path) {
1819
1941
  function scanBinaryForOAuthConfig(buf) {
1820
1942
  const binaryText = buf.toString("latin1");
1821
1943
  const candidates = extractCandidateBlocks(binaryText).map(extractCandidateFromBlock).filter((candidate) => candidate !== null).sort((left, right) => right.score - left.score);
1822
- return candidates[0]?.payload ?? null;
1944
+ const preferredCandidate = candidates.find((candidate) => candidate.payload.clientId === KNOWN_PROD_CLIENT_ID);
1945
+ return preferredCandidate?.payload ?? candidates[0]?.payload ?? null;
1946
+ }
1947
+ async function readRawCacheEntries() {
1948
+ const raw = await readFile(getCachePath(), "utf-8");
1949
+ const parsed = JSON.parse(raw);
1950
+ if (typeof parsed !== "object" || parsed === null || typeof parsed.entries !== "object" || parsed.entries === null) {
1951
+ return {};
1952
+ }
1953
+ return parsed.entries;
1823
1954
  }
1824
1955
  async function loadCache() {
1825
1956
  try {
1826
- const raw = await readFile(getCachePath(), "utf-8");
1827
- const parsed = JSON.parse(raw);
1828
- if (typeof parsed !== "object" || parsed === null || typeof parsed.entries !== "object" || parsed.entries === null) {
1829
- return {};
1830
- }
1957
+ const rawEntries = await readRawCacheEntries();
1831
1958
  const validEntries = {};
1832
- for (const [hash, value] of Object.entries(parsed.entries)) {
1833
- if (isDetectedOAuthConfigPayload(value)) {
1834
- validEntries[hash] = value;
1959
+ for (const [hash, value] of Object.entries(rawEntries)) {
1960
+ if (isDetectedOAuthConfigPayload(value) && !hasPollutedCachedScope(value.scopes)) {
1961
+ validEntries[hash] = normalizeDetectedOAuthConfigPayload(value);
1835
1962
  }
1836
1963
  }
1837
1964
  return validEntries;
@@ -1842,7 +1969,11 @@ async function loadCache() {
1842
1969
  async function saveCache(hash, config) {
1843
1970
  try {
1844
1971
  const cachePath = getCachePath();
1845
- const currentEntries = await loadCache();
1972
+ const currentEntries = {};
1973
+ try {
1974
+ Object.assign(currentEntries, await readRawCacheEntries());
1975
+ } catch {
1976
+ }
1846
1977
  currentEntries[hash] = config;
1847
1978
  await mkdir(dirname(cachePath), { recursive: true });
1848
1979
  await writeFile(
@@ -1867,27 +1998,23 @@ async function detectOAuthConfig() {
1867
1998
  const cachedEntries = await loadCache();
1868
1999
  const cachedConfig = cachedEntries[ccHash];
1869
2000
  if (cachedConfig) {
1870
- memoizedConfig = await applyManualOverride({
1871
- ...cachedConfig,
1872
- source: "cached",
1873
- ccPath,
1874
- ccHash
1875
- });
2001
+ memoizedConfig = await applyManualOverride(buildResolvedConfig(cachedConfig, "cached", ccPath, ccHash));
1876
2002
  return memoizedConfig;
1877
2003
  }
1878
2004
  const readBinaryFile = detectorTestOverrides.readBinaryFile || readFile;
1879
- const scannedConfig = scanBinaryForOAuthConfig(await readBinaryFile(ccPath));
2005
+ const binaryBuffer = await readBinaryFile(ccPath);
2006
+ const scannedConfig = scanBinaryForOAuthConfig(binaryBuffer);
1880
2007
  if (!scannedConfig) {
1881
2008
  memoizedConfig = await applyManualOverride(toFallbackConfig(ccPath, ccHash));
1882
2009
  return memoizedConfig;
1883
2010
  }
1884
- await saveCache(ccHash, scannedConfig);
1885
- memoizedConfig = await applyManualOverride({
1886
- ...scannedConfig,
1887
- source: "detected",
1888
- ccPath,
1889
- ccHash
1890
- });
2011
+ const verifiedCanonicalScopes = getVerifiedCanonicalScopes(binaryBuffer, FALLBACK.scopes);
2012
+ if (verifiedCanonicalScopes) {
2013
+ scannedConfig.scopes = verifiedCanonicalScopes;
2014
+ }
2015
+ const runtimeDetectedConfig = normalizeDetectedOAuthConfigPayload(scannedConfig);
2016
+ await saveCache(ccHash, runtimeDetectedConfig);
2017
+ memoizedConfig = await applyManualOverride(buildResolvedConfig(runtimeDetectedConfig, "detected", ccPath, ccHash));
1891
2018
  return memoizedConfig;
1892
2019
  } catch {
1893
2020
  memoizedConfig = await applyManualOverride(FALLBACK);
@@ -1895,7 +2022,7 @@ async function detectOAuthConfig() {
1895
2022
  }
1896
2023
  }
1897
2024
 
1898
- // src/fingerprint-capture.ts
2025
+ // src/claude-code/fingerprint/capture.ts
1899
2026
  var CURRENT_SCHEMA_VERSION = 1;
1900
2027
  var LIVE_TTL_MS = 24 * 60 * 60 * 1e3;
1901
2028
  var DEFAULT_CAPTURE_TIMEOUT_MS = 1e4;
@@ -1914,15 +2041,15 @@ var STATIC_HEADER_NAMES = [
1914
2041
  ];
1915
2042
  var SUPPORTED_CC_RANGE = {
1916
2043
  min: "1.0.0",
1917
- maxTested: "2.1.114"
2044
+ maxTested: "2.1.119"
1918
2045
  };
1919
- var bundledTemplate = fingerprint_data_default;
2046
+ var bundledTemplate = data_default;
1920
2047
  var fingerprintCaptureTestOverrides = {};
1921
2048
  function now() {
1922
2049
  return fingerprintCaptureTestOverrides.now?.() ?? Date.now();
1923
2050
  }
1924
2051
  function getCachePath2() {
1925
- return join2(getConfigDir(), CACHE_FILE_NAME2);
2052
+ return join2(fingerprintCaptureTestOverrides.getConfigDir?.() ?? getConfigDir(), CACHE_FILE_NAME2);
1926
2053
  }
1927
2054
  function isRecord(value) {
1928
2055
  return typeof value === "object" && value !== null;
@@ -2298,23 +2425,26 @@ function parseVersion(version) {
2298
2425
  if (!match) {
2299
2426
  return null;
2300
2427
  }
2301
- return [Number(match[1]), Number(match[2]), Number(match[3])];
2428
+ const [, major, minor, patch] = match;
2429
+ return [Number(major), Number(minor), Number(patch)];
2302
2430
  }
2303
2431
  function compareVersions(left, right) {
2304
- const leftVersion = parseVersion(left);
2305
- const rightVersion = parseVersion(right);
2306
- if (!leftVersion || !rightVersion) {
2432
+ const leftParts = parseVersion(left);
2433
+ const rightParts = parseVersion(right);
2434
+ if (!leftParts || !rightParts) {
2307
2435
  return null;
2308
2436
  }
2309
- for (let index = 0; index < leftVersion.length; index += 1) {
2310
- const leftPart = leftVersion[index] ?? 0;
2311
- const rightPart = rightVersion[index] ?? 0;
2312
- const diff = leftPart - rightPart;
2313
- if (diff !== 0) {
2314
- return diff;
2315
- }
2437
+ const [leftMajor, leftMinor, leftPatch] = leftParts;
2438
+ const [rightMajor, rightMinor, rightPatch] = rightParts;
2439
+ const majorDiff = leftMajor - rightMajor;
2440
+ if (majorDiff !== 0) {
2441
+ return majorDiff;
2316
2442
  }
2317
- return 0;
2443
+ const minorDiff = leftMinor - rightMinor;
2444
+ if (minorDiff !== 0) {
2445
+ return minorDiff;
2446
+ }
2447
+ return leftPatch - rightPatch;
2318
2448
  }
2319
2449
  function detectDrift(template, installedOverride) {
2320
2450
  const cachedVersion = template.cc_version ?? null;
@@ -2401,9 +2531,9 @@ function resetFingerprintCaptureForTest() {
2401
2531
  }
2402
2532
 
2403
2533
  export {
2404
- fingerprint_data_default,
2405
- detectCliVersion,
2406
- cc_derived_defaults_default,
2534
+ getConfig,
2535
+ loadConfig,
2536
+ updateConfigField,
2407
2537
  ANTHROPIC_OAUTH_ADAPTER,
2408
2538
  ANTHROPIC_USAGE_ENDPOINT,
2409
2539
  ANTHROPIC_PROFILE_ENDPOINT,
@@ -2412,9 +2542,9 @@ export {
2412
2542
  PLAN_LABELS,
2413
2543
  TOKEN_EXPIRY_BUFFER_MS,
2414
2544
  TOKEN_REFRESH_TIMEOUT_MS,
2415
- getConfig,
2416
- loadConfig,
2417
- updateConfigField,
2545
+ cc_derived_defaults_default,
2546
+ data_default,
2547
+ detectCliVersion,
2418
2548
  showToast,
2419
2549
  debugLog,
2420
2550
  createMinimalClient,
@@ -2431,9 +2561,10 @@ export {
2431
2561
  extractTemplate,
2432
2562
  captureLiveTemplateAsync,
2433
2563
  refreshLiveFingerprintAsync,
2564
+ compareVersions,
2434
2565
  detectDrift,
2435
2566
  checkCCCompat,
2436
2567
  setFingerprintCaptureTestOverridesForTest,
2437
2568
  resetFingerprintCaptureForTest
2438
2569
  };
2439
- //# sourceMappingURL=chunk-2SN3UVSM.js.map
2570
+ //# sourceMappingURL=chunk-II7N6KHL.js.map