@kili-ai/dev-install 0.2.64 → 0.2.65

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.
package/dist/index.js CHANGED
@@ -33,11 +33,11 @@ var import_node_http = require("http");
33
33
  var import_node_readline = require("readline");
34
34
 
35
35
  // src/constants.ts
36
- var PACKAGE_VERSION = true ? "0.2.64" : "0.1.0";
36
+ var PACKAGE_VERSION = true ? "0.2.65" : "0.1.0";
37
37
  var NPM_ORG = "kili-ai";
38
38
  var PACKAGE_NAME = `@${NPM_ORG}/ide.install`;
39
39
  var DEFAULT_WEB_URL = true ? "https://kili-ui.vercel.app/" : "https://app.trykili.ai";
40
- var DEFAULT_API_URL = true ? "https://app-dev.trykili.ai" : "https://api.trykili.ai";
40
+ var DEFAULT_API_URL = true ? "https://api-dev.trykili.ai" : "https://api.trykili.ai";
41
41
  var CLI_AUTH_PATH = "/cli-auth";
42
42
  var AUTH_TIMEOUT_MS = 5 * 60 * 1e3;
43
43
  var EXTENSION_ID = true ? "kili-ai.kili-ide-dev" : "kili-ai.kili-ide";
@@ -8,7 +8,7 @@ var import_node_crypto = require("crypto");
8
8
  var NPM_ORG = "kili-ai";
9
9
  var NPM_PACKAGE = "ide";
10
10
  var PACKAGE_NAME = `@${NPM_ORG}/${NPM_PACKAGE}`;
11
- var DEFAULT_API_URL = true ? "https://app-dev.trykili.ai" : "https://api.trykili.ai";
11
+ var DEFAULT_API_URL = true ? "https://api-dev.trykili.ai" : "https://api.trykili.ai";
12
12
  var DEFAULT_WEB_URL = true ? "https://kili-ui.vercel.app/" : "https://app.trykili.ai";
13
13
  var AUTH_TIMEOUT_MS = 5 * 60 * 1e3;
14
14
  var PLACEMENT = {
@@ -1539,14 +1539,10 @@ async function fetchAndCacheLogoDataUri(url) {
1539
1539
  // src/core/refresh.ts
1540
1540
  var _ALL_PLACEMENTS = [
1541
1541
  PLACEMENT.TERMINAL_SPINNER,
1542
- PLACEMENT.EXTENSION_SPINNER,
1543
- PLACEMENT.EXTENSION_STATUSBAR
1542
+ PLACEMENT.EXTENSION_SPINNER
1544
1543
  ];
1545
1544
  var TERMINAL_PLACEMENTS = [PLACEMENT.TERMINAL_SPINNER];
1546
- var EXTENSION_PLACEMENTS = [
1547
- PLACEMENT.EXTENSION_SPINNER,
1548
- PLACEMENT.EXTENSION_STATUSBAR
1549
- ];
1545
+ var EXTENSION_PLACEMENTS = [PLACEMENT.EXTENSION_SPINNER];
1550
1546
  async function refreshAllPlacements(config, sessionId, placementIds = _ALL_PLACEMENTS) {
1551
1547
  const client = new KiliClient();
1552
1548
  const adSets = await client.fetchAds({
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/client.ts","../src/core/constants.ts","../src/core/debug.ts","../src/core/paths.ts","../src/core/errors.ts","../src/core/store.ts","../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js","../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/string-intern.js","../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/parser.js","../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/main.js","../src/core/cache.ts","../src/core/config.ts","../src/core/webviewPatch.ts","../src/core/copy.ts","../src/core/editorSettings.ts","../src/claude/settings.ts","../src/core/logoCache.ts","../src/core/refresh.ts","../src/hook.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { DEFAULT_API_URL, ERRORS } from \"./constants\";\nimport { debugLog } from \"./debug\";\nimport { KiliError } from \"./errors\";\nimport type { TAd, TAdsResult } from \"./types\";\n\nconst _defaultTimeoutMs = 5000;\n\nexport type TFetchAdsInput = {\n\tapiKey: string;\n\tapiUrl?: string;\n\t/** Every placement id fetched in one request/round trip -- api.kili's\n\t * `/ads` already accepts a `placements[]` array, and resolves one\n\t * relevant ad per request that it reuses across every placement passed\n\t * in. Requesting a caller's several surfaces together therefore both\n\t * costs one call instead of one per surface, and is what keeps every\n\t * surface showing the same single ad -- each placement still gets its\n\t * own trackId, so impressions/clicks are billed independently even\n\t * though the ad content is shared. */\n\tplacementIds: string[];\n\tsessionId: string;\n\tinstallId: string;\n};\n\n/**\n * Ports `pkg.api.cherry`'s `KiliApiClient.getAds` for a Node/VS Code caller\n * instead of an incoming HTTP request -- same wire contract\n * (`api.kili/src/transformers/ads.transformer.ts`).\n */\nexport class KiliClient {\n\t/** Keyed by placement id, value is every ad api.kili served for that\n\t * placement, in the order the server returned them -- how many that is\n\t * per call depends entirely on which `IAdServeStrategy` is configured\n\t * server-side (currently `RandomAdServeStrategy`, one ad; `ads.service.ts`\n\t * can also serve a whole shuffled candidate list under `AllAdServeStrategy`).\n\t * Either way this is grouped into an array per placement, never a single\n\t * value, so the client never has to know or care which strategy is live.\n\t * A placement api.kili had nothing to serve for (e.g. no active campaign)\n\t * simply has no entry -- callers should treat a missing key exactly like\n\t * \"no ad\", the same as an empty `ads[]` today. Grouping, not the old\n\t * `new Map(...)` overwrite: a `Map` built from `[placementId, ad]` pairs\n\t * silently keeps only the *last* entry for a repeated key, which is\n\t * exactly what used to throw away every ad but one under\n\t * `AllAdServeStrategy` -- confirmed live as the root cause of \"same ad\n\t * every time\". */\n\tpublic async fetchAds(input: TFetchAdsInput): Promise<Map<string, TAd[]>> {\n\t\tif (!input.apiKey) {\n\t\t\tthrow new KiliError(ERRORS.REQUIRED_API_KEY, 401);\n\t\t}\n\t\tconst baseUrl = input.apiUrl ?? DEFAULT_API_URL;\n\t\tconst result = await this._request(baseUrl, input);\n\t\t// KILI_DEBUG=1 only -- lets `favicon` (the ad's logo, see\n\t\t// `copy.ts`'s `spinnerVerbLink`) be confirmed present or absent in\n\t\t// the raw wire response, one hop before anything gets encoded into\n\t\t// a spinner verb or written to a webview.\n\t\tdebugLog(\n\t\t\t\"fetchAds\",\n\t\t\tresult.ads.map((ad) => ({\n\t\t\t\tplacementId: ad.placementId,\n\t\t\t\tadId: ad.adId,\n\t\t\t\thasFavicon: Boolean(ad.favicon),\n\t\t\t\tfavicon: ad.favicon,\n\t\t\t})),\n\t\t);\n\t\tconst grouped = new Map<string, TAd[]>();\n\t\tfor (const ad of result.ads) {\n\t\t\tconst list = grouped.get(ad.placementId);\n\t\t\tif (list) list.push(ad);\n\t\t\telse grouped.set(ad.placementId, [ad]);\n\t\t}\n\t\treturn grouped;\n\t}\n\n\tprivate async _request(\n\t\tbaseUrl: string,\n\t\tinput: TFetchAdsInput,\n\t): Promise<TAdsResult> {\n\t\tconst controller = new AbortController();\n\t\tconst timer = setTimeout(() => controller.abort(), _defaultTimeoutMs);\n\t\ttry {\n\t\t\tconst res = await fetch(`${baseUrl}/ads`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"content-type\": \"application/json\",\n\t\t\t\t\t\"x-kili-api-key\": input.apiKey,\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify(this._body(input)),\n\t\t\t\tsignal: controller.signal,\n\t\t\t});\n\t\t\tif (!res.ok) {\n\t\t\t\tthrow new KiliError(ERRORS.REQUEST_FAILED, res.status);\n\t\t\t}\n\t\t\treturn (await res.json()) as TAdsResult;\n\t\t} catch (error) {\n\t\t\tthrow this._toKiliError(error);\n\t\t} finally {\n\t\t\tclearTimeout(timer);\n\t\t}\n\t}\n\n\tprivate _body(input: TFetchAdsInput) {\n\t\treturn {\n\t\t\t// No `messages` field -- api.kili's ad selection (`RandomAdServeStrategy`\n\t\t\t// / `AllAdServeStrategy`, and the `IAdServeStrategy` interface itself)\n\t\t\t// never reads conversation content at all, so sending it here was pure\n\t\t\t// dead weight: payload size and server-side parsing for a field nothing\n\t\t\t// picks on. The wire schema still accepts it (optional, defaults to\n\t\t\t// `[]` server-side) for any other caller and for a future relevancy\n\t\t\t// strategy -- we just stopped being the one paying for it.\n\t\t\t// `placement` carries our own distinguishing value directly (see\n\t\t\t// PLACEMENT in constants.ts) rather than a shared generic slot type\n\t\t\t// -- that's the only field that lands in `ad_events`, so it has to be\n\t\t\t// the one that tells our four surfaces apart. `placementId` is still\n\t\t\t// a required wire field; sending the same value keeps the two in\n\t\t\t// sync without adding a second meaning to track.\n\t\t\tplacements: input.placementIds.map((placementId) => ({\n\t\t\t\tplacement: placementId,\n\t\t\t\tplacementId,\n\t\t\t})),\n\t\t\tkiliContext: {\n\t\t\t\tsessionId: this._sessionId(input.sessionId),\n\t\t\t\tuser: { userId: input.installId },\n\t\t\t\tdevice: {\n\t\t\t\t\tua: \"@kili-ai/ide\",\n\t\t\t\t\ttimezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n\t\t\t\t\tlocale: Intl.DateTimeFormat().resolvedOptions().locale,\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n\n\t/** api.kili requires a UUID; fall back to a fresh one when Claude's own\n\t * `session_id` doesn't parse as one. */\n\tprivate _sessionId(raw: string): string {\n\t\tconst uuidPattern =\n\t\t\t/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\t\treturn uuidPattern.test(raw) ? raw : randomUUID();\n\t}\n\n\tprivate _toKiliError(error: unknown): KiliError {\n\t\tif (error instanceof KiliError) return error;\n\t\tif (error instanceof Error && error.name === \"AbortError\") {\n\t\t\treturn new KiliError(ERRORS.TIMEOUT, 408);\n\t\t}\n\t\treturn new KiliError(ERRORS.NETWORK, 503);\n\t}\n}\n\n/**\n * Fire-and-forget beacon for `impUrl` / `clickUrl`. Never throws.\n *\n * Unlike a click (a real browser navigation straight to `clickUrl` -- if\n * `/track` rejects it, the browser itself shows an error page, so a broken\n * click is hard to miss), an impression's `/ack` call goes through this\n * function with nothing else ever inspecting the result. `fetch()` only\n * throws on network-level failures (DNS, connection refused, timeout) --\n * NOT on a 4xx/5xx response, so a server-side rejection (expired/malformed\n * JWT, `/ack` erroring) used to look identical to success from here: no\n * exception, `catch` never runs, caller marks the impression fired and moves\n * on, and the dashboard just never sees it. Logging `res.status` on every\n * call (only under `KILI_DEBUG=1`) is what makes that distinguishable from\n * an actually-successful beacon.\n */\nexport async function beacon(url: string | undefined): Promise<void> {\n\tif (!url) return;\n\ttry {\n\t\tconst res = await fetch(url, { method: \"GET\" });\n\t\tdebugLog(\"beacon\", { url, status: res.status, ok: res.ok });\n\t} catch (error) {\n\t\t// Billing beacons are best-effort from the client's side -- a dropped\n\t\t// beacon should never crash a spinner or a hook.\n\t\tdebugLog(\n\t\t\t\"beacon: threw\",\n\t\t\t{ url },\n\t\t\terror instanceof Error ? error.message : error,\n\t\t);\n\t}\n}\n","declare const __PACKAGE_VERSION__: string;\ndeclare const __DEFAULT_API_URL__: string;\ndeclare const __DEFAULT_WEB_URL__: string;\n\nexport const PACKAGE_VERSION =\n\ttypeof __PACKAGE_VERSION__ !== \"undefined\" ? __PACKAGE_VERSION__ : \"0.1.0\";\n\nexport const NPM_ORG = \"kili-ai\";\nexport const NPM_PACKAGE = \"ide\";\nexport const PACKAGE_NAME = `@${NPM_ORG}/${NPM_PACKAGE}`;\n\n/**\n * This literal fallback is always the PROD url, on every branch, including\n * `dev` -- never hand-edited per branch. A dev publish overrides it via\n * `KILI_API_URL`/`KILI_WEB_URL` (see `tsup.config.ts`), set only for the\n * duration of that one build/publish by `pkg.install.kili`'s\n * `scripts/publish-channel.cjs`, which also temporarily patches\n * `contributes.configuration.kili.apiUrl/webUrl`'s defaults in\n * `package.json` the same way and restores both files afterward. Keeping\n * dev/prod identity purely a publish-time concern, never a committed diff\n * between branches, is deliberate: `dev` and `master` are meant to be\n * merged into each other as normal feature work lands, and a real diff\n * here would silently carry one channel's URLs into the other on merge.\n */\nexport const DEFAULT_API_URL =\n\ttypeof __DEFAULT_API_URL__ !== \"undefined\"\n\t\t? __DEFAULT_API_URL__\n\t\t: \"https://api.trykili.ai\";\nexport const DEFAULT_WEB_URL =\n\ttypeof __DEFAULT_WEB_URL__ !== \"undefined\"\n\t\t? __DEFAULT_WEB_URL__\n\t\t: \"https://app.trykili.ai\";\nexport const CLI_AUTH_PATH = \"/cli-auth\";\nexport const AUTH_TIMEOUT_MS = 5 * 60 * 1000;\n\n/**\n * Distinct placement ids per surface, self-descriptive on their own in\n * `ad_events` -- no cross-referencing code to know a\n * \"claude_code_extension_spinner\" row came from this package's editor\n * sidebar, not the terminal. Named `<app>_<surface>` throughout: `terminal`\n * for the CLI, `extension` for the VS Code/Cursor sidebar; `spinner` (text,\n * impression-only, can't be clicked) vs `statusline`/`statusbar` (rendered\n * by us, clickable). Each gets served in the same `/ads` call as its\n * sibling surface but is still a fully separate placement -- separately\n * priced, separately reported, never sharing one fetched ad relabeled two\n * ways.\n */\nexport const PLACEMENT = {\n\tTERMINAL_SPINNER: \"claude_code_terminal_spinner\",\n\tTERMINAL_STATUSLINE: \"claude_code_terminal_statusline\",\n\tEXTENSION_SPINNER: \"claude_code_extension_spinner\",\n\tEXTENSION_STATUSBAR: \"claude_code_extension_statusbar\",\n} as const;\n\n/**\n * How long an ad must be continuously visible before we consider it a real\n * impression and fire `impUrl`. Was 10s (a standard \"qualifying view\"\n * convention), lowered to 3s, then to 0 on request --\n * \"shown is enough, no time limit\". At 0, `markRenderedAndClaimImpression`\n * still needs a second render call to fire (its first call only records\n * `firstSeenAt`), so it's \"next render tick\" rather than truly instant --\n * but for `settlePendingTurn`, 0 means every turn that completes at all\n * qualifies, however short. This is a real tradeoff, not a free tuning\n * knob: it removes any distinction between an ad that was actually seen and\n * one that flickered past for a fraction of a second before the next turn\n * replaced it.\n */\nexport const DWELL_THRESHOLD_MS = 0;\n\nexport const ERRORS = {\n\tREQUIRED_API_KEY: 'Kili API key is required. Run \"Kili: Sign In\".',\n\tREQUEST_FAILED: \"Kili request failed.\",\n\tTIMEOUT: \"Kili request timed out.\",\n\tNETWORK: \"Kili network error.\",\n};\n","import { appendFileSync, mkdirSync, renameSync, statSync } from \"node:fs\";\nimport { basename, dirname } from \"node:path\";\nimport { debugLogPath } from \"./paths\";\n\n/**\n * Logs to `~/.kili/debug.log` ALWAYS, and additionally to stderr when\n * `KILI_DEBUG=1`.\n *\n * The file is the point. Two of the three processes in this package are\n * one-shot children spawned by Claude Code -- `hook.ts` (per turn) and\n * `statusline.ts` (roughly every 300ms) -- and neither one's stderr is\n * displayed anywhere a user or a developer can see it. For most of this\n * package's life that meant the per-turn ad path, the single most\n * bug-prone thing here, produced no observable trace at all: diagnosing it\n * came down to reading `~/.kili/*.json` mtimes and guessing at ordering\n * between three processes. A durable, timestamped, process-tagged file\n * removes the guessing.\n *\n * Never stdout -- `hook.ts`'s stdout is read by Claude Code and, for\n * `UserPromptSubmit`, injected into the model's own context, so anything\n * printed there must be exactly what that hook contract expects and nothing\n * else. Never throws, either: logging must never be able to break the ad\n * path it exists to observe.\n */\n\n/** Rotated (not truncated) at this size so the previous window survives one\n * more run -- a bug reproduced once tends to get looked at after the fact,\n * and dropping the only copy of that evidence to save a few hundred KB is a\n * bad trade. */\nconst _MAX_BYTES = 256_000;\n\n/** Which of the three processes wrote a line. `hook`/`statusline` are the\n * ones with nowhere else to log; `extension` runs in the extension host and\n * also has an Output channel, but shares this file so one timeline covers\n * all three. */\nfunction _processTag(): string {\n\tconst entry = process.argv[1];\n\tif (!entry) return \"?\";\n\tconst name = basename(entry).replace(/\\.[cm]?js$/, \"\");\n\treturn name || \"?\";\n}\n\nfunction _rotateIfLarge(path: string): void {\n\ttry {\n\t\tif (statSync(path).size < _MAX_BYTES) return;\n\t\trenameSync(path, `${path}.1`);\n\t} catch {\n\t\t/* no file yet, or rotation raced another process -- either is fine */\n\t}\n}\n\nfunction _format(args: unknown[]): string {\n\treturn args\n\t\t.map((arg) => {\n\t\t\tif (typeof arg === \"string\") return arg;\n\t\t\tif (arg instanceof Error) return `${arg.name}: ${arg.message}`;\n\t\t\ttry {\n\t\t\t\treturn JSON.stringify(arg);\n\t\t\t} catch {\n\t\t\t\treturn String(arg);\n\t\t\t}\n\t\t})\n\t\t.join(\" \");\n}\n\nexport function debugLog(...args: unknown[]): void {\n\tif (process.env.KILI_DEBUG === \"1\") {\n\t\tconsole.error(\"[kili]\", ...args);\n\t}\n\ttry {\n\t\tconst path = debugLogPath();\n\t\tmkdirSync(dirname(path), { recursive: true });\n\t\t_rotateIfLarge(path);\n\t\tconst line = `${new Date().toISOString()} [${_processTag()}] ${_format(args)}\\n`;\n\t\tappendFileSync(path, line, \"utf8\");\n\t} catch {\n\t\t/* logging must never break the caller -- see this file's doc comment */\n\t}\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\n/** Kili's own state directory -- separate from `~/.claude`, since we never\n * want a bug in our code to risk corrupting Claude's own state. */\nexport function kiliHome(): string {\n\treturn join(homedir(), \".kili\");\n}\n\nexport function adCachePath(): string {\n\treturn join(kiliHome(), \"ad-cache.json\");\n}\n\n/** Data-URI cache for logo images (see `logoCache.ts`), keyed by their\n * original remote URL. Separate file from `ad-cache.json` because it\n * outlives any single ad -- the same brand's logo URL recurs across many\n * different ads/campaigns, so the fetch-and-encode cost should only ever be\n * paid once per URL, not once per ad. */\nexport function logoCachePath(): string {\n\treturn join(kiliHome(), \"logo-cache.json\");\n}\n\nexport function pendingTurnPath(): string {\n\treturn join(kiliHome(), \"pending-turn.json\");\n}\n\n/** Written by `statusline.ts` on every invocation -- the only reliable\n * signal that a real terminal is actually rendering `statusLine` right now.\n * The IDE chat panel never runs this script (it reads `claudeCode.spinnerVerbs`\n * straight from its own webview, a completely separate mechanism), so a\n * fresh heartbeat here means a real terminal, not the chat panel, is what's\n * currently in front of the user. See `isTerminalActive` in `cache.ts`. */\nexport function terminalHeartbeatPath(): string {\n\treturn join(kiliHome(), \"terminal-heartbeat.json\");\n}\n\nexport function runtimeConfigPath(): string {\n\treturn join(kiliHome(), \"config.json\");\n}\n\n/** Where `debug.ts` writes its always-on log. One file shared by all three\n * processes (`extension`, `hook`, `statusline`) on purpose -- the bugs worth\n * diagnosing here are ordering bugs *between* them, which a per-process file\n * would split apart. */\nexport function debugLogPath(): string {\n\treturn join(kiliHome(), \"debug.log\");\n}\n\nexport function settingsBackupPath(): string {\n\treturn join(kiliHome(), \"settings.backup.json\");\n}\n\nexport function claudeSettingsPath(): string {\n\treturn join(homedir(), \".claude\", \"settings.json\");\n}\n","export class KiliError extends Error {\n\tpublic readonly statusCode: number;\n\n\tconstructor(message: string, statusCode: number) {\n\t\tsuper(message);\n\t\tthis.name = \"KiliError\";\n\t\tthis.statusCode = statusCode;\n\t}\n}\n","import {\n\texistsSync,\n\tmkdirSync,\n\treadFileSync,\n\trenameSync,\n\tunlinkSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport {\n\ttype ParseError,\n\tparse as parseJsonc,\n\tprintParseErrorCode,\n} from \"jsonc-parser\";\n\n/**\n * Atomic JSON read/write for the cache files three separate OS processes\n * touch concurrently: the extension host's refresh timer, `statusline.ts`\n * (spawned fresh on every render by Claude Code), and `hook.ts` (spawned\n * fresh on every turn). Writing to a temp file and renaming over the target\n * means a reader never observes a half-written file.\n */\n\nexport function readJson<T>(path: string, fallback: T): T {\n\tif (!existsSync(path)) return fallback;\n\ttry {\n\t\treturn JSON.parse(readFileSync(path, \"utf8\")) as T;\n\t} catch {\n\t\treturn fallback;\n\t}\n}\n\n/**\n * Thrown by `readJsonOwnedByUser` when a file exists but can't be parsed --\n * never caught silently by that function itself, unlike `readJson`.\n */\nexport class SettingsParseError extends Error {}\n\n/**\n * For files we don't own -- the user's editor `settings.json`, or\n * `~/.claude/settings.json` -- never `readJson`. That function treats \"I\n * couldn't parse this\" the same as \"the file doesn't exist\", which is\n * correct for our own cache files (nobody else ever hand-edits\n * `~/.kili/ad-cache.json`) but is real data loss here: VS Code's own\n * settings.json commonly has `//` comments and trailing commas (JSONC,\n * which the editor accepts fine but `JSON.parse` doesn't), so a perfectly\n * normal settings.json would silently look \"empty\" to a merge-write --\n * which then writes back *only* our own key, discarding the user's theme,\n * activity bar layout, everything else in the file. Confirmed: this\n * happened for real.\n *\n * Parsed with `jsonc-parser` (the same library VS Code's own settings UI\n * uses), NOT `JSON.parse` -- a bare `JSON.parse` used to reject comments and\n * trailing commas outright, which meant an ordinary, valid settings.json\n * (comments are completely normal there) permanently threw here and blocked\n * every write forever, e.g. `kili.apiKey` never landing on sign-in.\n * Confirmed live: this happened for real too, on a ordinary hand-commented\n * settings.json, not a corrupted one. `allowTrailingComma: true` because\n * VS Code's editor accepts those on save; comments need no explicit opt-in,\n * `parse()` always tolerates them.\n *\n * Missing file -> `fallback` (nothing to lose, safe to start fresh).\n * Existing but genuinely unparseable file (real syntax errors beyond\n * JSONC's comments/trailing commas) -> throws, so the caller aborts the\n * write instead of clobbering it. Callers must catch this and skip/warn,\n * not crash outright -- see `claude/settings.ts` and `editorSettings.ts`.\n */\nexport function readJsonOwnedByUser<T>(path: string, fallback: T): T {\n\tif (!existsSync(path)) return fallback;\n\tconst text = readFileSync(path, \"utf8\");\n\tconst errors: ParseError[] = [];\n\tconst parsed = parseJsonc(text, errors, { allowTrailingComma: true });\n\tif (errors.length > 0) {\n\t\tconst first = errors[0];\n\t\tthrow new SettingsParseError(\n\t\t\t`${path} exists but could not be parsed as JSON, even allowing for ` +\n\t\t\t\t`JSONC comments/trailing commas -- refusing to overwrite it. ` +\n\t\t\t\t`(${printParseErrorCode(first.error)} at offset ${first.offset})`,\n\t\t);\n\t}\n\treturn parsed as T;\n}\n\nexport function writeJsonAtomic(path: string, value: unknown): void {\n\tmkdirSync(dirname(path), { recursive: true });\n\tconst tmp = `${path}.tmp-${process.pid}-${Date.now()}`;\n\twriteFileSync(tmp, JSON.stringify(value), \"utf8\");\n\ttry {\n\t\trenameSync(tmp, path);\n\t} catch {\n\t\t// Cross-device rename can fail on some Windows setups -- fall back to\n\t\t// a direct write, which is not atomic but still correct absent a\n\t\t// concurrent writer mid-read.\n\t\twriteFileSync(path, JSON.stringify(value), \"utf8\");\n\t\ttry {\n\t\t\tunlinkSync(tmp);\n\t\t} catch {\n\t\t\t/* best effort cleanup */\n\t\t}\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n'use strict';\n/**\n * Creates a JSON scanner on the given text.\n * If ignoreTrivia is set, whitespaces or comments are ignored.\n */\nexport function createScanner(text, ignoreTrivia = false) {\n const len = text.length;\n let pos = 0, value = '', tokenOffset = 0, token = 16 /* SyntaxKind.Unknown */, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0 /* ScanError.None */;\n function scanHexDigits(count, exact) {\n let digits = 0;\n let value = 0;\n while (digits < count || !exact) {\n let ch = text.charCodeAt(pos);\n if (ch >= 48 /* CharacterCodes._0 */ && ch <= 57 /* CharacterCodes._9 */) {\n value = value * 16 + ch - 48 /* CharacterCodes._0 */;\n }\n else if (ch >= 65 /* CharacterCodes.A */ && ch <= 70 /* CharacterCodes.F */) {\n value = value * 16 + ch - 65 /* CharacterCodes.A */ + 10;\n }\n else if (ch >= 97 /* CharacterCodes.a */ && ch <= 102 /* CharacterCodes.f */) {\n value = value * 16 + ch - 97 /* CharacterCodes.a */ + 10;\n }\n else {\n break;\n }\n pos++;\n digits++;\n }\n if (digits < count) {\n value = -1;\n }\n return value;\n }\n function setPosition(newPosition) {\n pos = newPosition;\n value = '';\n tokenOffset = 0;\n token = 16 /* SyntaxKind.Unknown */;\n scanError = 0 /* ScanError.None */;\n }\n function scanNumber() {\n let start = pos;\n if (text.charCodeAt(pos) === 48 /* CharacterCodes._0 */) {\n pos++;\n }\n else {\n pos++;\n while (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n }\n }\n if (pos < text.length && text.charCodeAt(pos) === 46 /* CharacterCodes.dot */) {\n pos++;\n if (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n while (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n }\n }\n else {\n scanError = 3 /* ScanError.UnexpectedEndOfNumber */;\n return text.substring(start, pos);\n }\n }\n let end = pos;\n if (pos < text.length && (text.charCodeAt(pos) === 69 /* CharacterCodes.E */ || text.charCodeAt(pos) === 101 /* CharacterCodes.e */)) {\n pos++;\n if (pos < text.length && text.charCodeAt(pos) === 43 /* CharacterCodes.plus */ || text.charCodeAt(pos) === 45 /* CharacterCodes.minus */) {\n pos++;\n }\n if (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n while (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n }\n end = pos;\n }\n else {\n scanError = 3 /* ScanError.UnexpectedEndOfNumber */;\n }\n }\n return text.substring(start, end);\n }\n function scanString() {\n let result = '', start = pos;\n while (true) {\n if (pos >= len) {\n result += text.substring(start, pos);\n scanError = 2 /* ScanError.UnexpectedEndOfString */;\n break;\n }\n const ch = text.charCodeAt(pos);\n if (ch === 34 /* CharacterCodes.doubleQuote */) {\n result += text.substring(start, pos);\n pos++;\n break;\n }\n if (ch === 92 /* CharacterCodes.backslash */) {\n result += text.substring(start, pos);\n pos++;\n if (pos >= len) {\n scanError = 2 /* ScanError.UnexpectedEndOfString */;\n break;\n }\n const ch2 = text.charCodeAt(pos++);\n switch (ch2) {\n case 34 /* CharacterCodes.doubleQuote */:\n result += '\\\"';\n break;\n case 92 /* CharacterCodes.backslash */:\n result += '\\\\';\n break;\n case 47 /* CharacterCodes.slash */:\n result += '/';\n break;\n case 98 /* CharacterCodes.b */:\n result += '\\b';\n break;\n case 102 /* CharacterCodes.f */:\n result += '\\f';\n break;\n case 110 /* CharacterCodes.n */:\n result += '\\n';\n break;\n case 114 /* CharacterCodes.r */:\n result += '\\r';\n break;\n case 116 /* CharacterCodes.t */:\n result += '\\t';\n break;\n case 117 /* CharacterCodes.u */:\n const ch3 = scanHexDigits(4, true);\n if (ch3 >= 0) {\n result += String.fromCharCode(ch3);\n }\n else {\n scanError = 4 /* ScanError.InvalidUnicode */;\n }\n break;\n default:\n scanError = 5 /* ScanError.InvalidEscapeCharacter */;\n }\n start = pos;\n continue;\n }\n if (ch >= 0 && ch <= 0x1f) {\n if (isLineBreak(ch)) {\n result += text.substring(start, pos);\n scanError = 2 /* ScanError.UnexpectedEndOfString */;\n break;\n }\n else {\n scanError = 6 /* ScanError.InvalidCharacter */;\n // mark as error but continue with string\n }\n }\n pos++;\n }\n return result;\n }\n function scanNext() {\n value = '';\n scanError = 0 /* ScanError.None */;\n tokenOffset = pos;\n lineStartOffset = lineNumber;\n prevTokenLineStartOffset = tokenLineStartOffset;\n if (pos >= len) {\n // at the end\n tokenOffset = len;\n return token = 17 /* SyntaxKind.EOF */;\n }\n let code = text.charCodeAt(pos);\n // trivia: whitespace\n if (isWhiteSpace(code)) {\n do {\n pos++;\n value += String.fromCharCode(code);\n code = text.charCodeAt(pos);\n } while (isWhiteSpace(code));\n return token = 15 /* SyntaxKind.Trivia */;\n }\n // trivia: newlines\n if (isLineBreak(code)) {\n pos++;\n value += String.fromCharCode(code);\n if (code === 13 /* CharacterCodes.carriageReturn */ && text.charCodeAt(pos) === 10 /* CharacterCodes.lineFeed */) {\n pos++;\n value += '\\n';\n }\n lineNumber++;\n tokenLineStartOffset = pos;\n return token = 14 /* SyntaxKind.LineBreakTrivia */;\n }\n switch (code) {\n // tokens: []{}:,\n case 123 /* CharacterCodes.openBrace */:\n pos++;\n return token = 1 /* SyntaxKind.OpenBraceToken */;\n case 125 /* CharacterCodes.closeBrace */:\n pos++;\n return token = 2 /* SyntaxKind.CloseBraceToken */;\n case 91 /* CharacterCodes.openBracket */:\n pos++;\n return token = 3 /* SyntaxKind.OpenBracketToken */;\n case 93 /* CharacterCodes.closeBracket */:\n pos++;\n return token = 4 /* SyntaxKind.CloseBracketToken */;\n case 58 /* CharacterCodes.colon */:\n pos++;\n return token = 6 /* SyntaxKind.ColonToken */;\n case 44 /* CharacterCodes.comma */:\n pos++;\n return token = 5 /* SyntaxKind.CommaToken */;\n // strings\n case 34 /* CharacterCodes.doubleQuote */:\n pos++;\n value = scanString();\n return token = 10 /* SyntaxKind.StringLiteral */;\n // comments\n case 47 /* CharacterCodes.slash */:\n const start = pos - 1;\n // Single-line comment\n if (text.charCodeAt(pos + 1) === 47 /* CharacterCodes.slash */) {\n pos += 2;\n while (pos < len) {\n if (isLineBreak(text.charCodeAt(pos))) {\n break;\n }\n pos++;\n }\n value = text.substring(start, pos);\n return token = 12 /* SyntaxKind.LineCommentTrivia */;\n }\n // Multi-line comment\n if (text.charCodeAt(pos + 1) === 42 /* CharacterCodes.asterisk */) {\n pos += 2;\n const safeLength = len - 1; // For lookahead.\n let commentClosed = false;\n while (pos < safeLength) {\n const ch = text.charCodeAt(pos);\n if (ch === 42 /* CharacterCodes.asterisk */ && text.charCodeAt(pos + 1) === 47 /* CharacterCodes.slash */) {\n pos += 2;\n commentClosed = true;\n break;\n }\n pos++;\n if (isLineBreak(ch)) {\n if (ch === 13 /* CharacterCodes.carriageReturn */ && text.charCodeAt(pos) === 10 /* CharacterCodes.lineFeed */) {\n pos++;\n }\n lineNumber++;\n tokenLineStartOffset = pos;\n }\n }\n if (!commentClosed) {\n pos++;\n scanError = 1 /* ScanError.UnexpectedEndOfComment */;\n }\n value = text.substring(start, pos);\n return token = 13 /* SyntaxKind.BlockCommentTrivia */;\n }\n // just a single slash\n value += String.fromCharCode(code);\n pos++;\n return token = 16 /* SyntaxKind.Unknown */;\n // numbers\n case 45 /* CharacterCodes.minus */:\n value += String.fromCharCode(code);\n pos++;\n if (pos === len || !isDigit(text.charCodeAt(pos))) {\n return token = 16 /* SyntaxKind.Unknown */;\n }\n // found a minus, followed by a number so\n // we fall through to proceed with scanning\n // numbers\n case 48 /* CharacterCodes._0 */:\n case 49 /* CharacterCodes._1 */:\n case 50 /* CharacterCodes._2 */:\n case 51 /* CharacterCodes._3 */:\n case 52 /* CharacterCodes._4 */:\n case 53 /* CharacterCodes._5 */:\n case 54 /* CharacterCodes._6 */:\n case 55 /* CharacterCodes._7 */:\n case 56 /* CharacterCodes._8 */:\n case 57 /* CharacterCodes._9 */:\n value += scanNumber();\n return token = 11 /* SyntaxKind.NumericLiteral */;\n // literals and unknown symbols\n default:\n // is a literal? Read the full word.\n while (pos < len && isUnknownContentCharacter(code)) {\n pos++;\n code = text.charCodeAt(pos);\n }\n if (tokenOffset !== pos) {\n value = text.substring(tokenOffset, pos);\n // keywords: true, false, null\n switch (value) {\n case 'true': return token = 8 /* SyntaxKind.TrueKeyword */;\n case 'false': return token = 9 /* SyntaxKind.FalseKeyword */;\n case 'null': return token = 7 /* SyntaxKind.NullKeyword */;\n }\n return token = 16 /* SyntaxKind.Unknown */;\n }\n // some\n value += String.fromCharCode(code);\n pos++;\n return token = 16 /* SyntaxKind.Unknown */;\n }\n }\n function isUnknownContentCharacter(code) {\n if (isWhiteSpace(code) || isLineBreak(code)) {\n return false;\n }\n switch (code) {\n case 125 /* CharacterCodes.closeBrace */:\n case 93 /* CharacterCodes.closeBracket */:\n case 123 /* CharacterCodes.openBrace */:\n case 91 /* CharacterCodes.openBracket */:\n case 34 /* CharacterCodes.doubleQuote */:\n case 58 /* CharacterCodes.colon */:\n case 44 /* CharacterCodes.comma */:\n case 47 /* CharacterCodes.slash */:\n return false;\n }\n return true;\n }\n function scanNextNonTrivia() {\n let result;\n do {\n result = scanNext();\n } while (result >= 12 /* SyntaxKind.LineCommentTrivia */ && result <= 15 /* SyntaxKind.Trivia */);\n return result;\n }\n return {\n setPosition: setPosition,\n getPosition: () => pos,\n scan: ignoreTrivia ? scanNextNonTrivia : scanNext,\n getToken: () => token,\n getTokenValue: () => value,\n getTokenOffset: () => tokenOffset,\n getTokenLength: () => pos - tokenOffset,\n getTokenStartLine: () => lineStartOffset,\n getTokenStartCharacter: () => tokenOffset - prevTokenLineStartOffset,\n getTokenError: () => scanError,\n };\n}\nfunction isWhiteSpace(ch) {\n return ch === 32 /* CharacterCodes.space */ || ch === 9 /* CharacterCodes.tab */;\n}\nfunction isLineBreak(ch) {\n return ch === 10 /* CharacterCodes.lineFeed */ || ch === 13 /* CharacterCodes.carriageReturn */;\n}\nfunction isDigit(ch) {\n return ch >= 48 /* CharacterCodes._0 */ && ch <= 57 /* CharacterCodes._9 */;\n}\nvar CharacterCodes;\n(function (CharacterCodes) {\n CharacterCodes[CharacterCodes[\"lineFeed\"] = 10] = \"lineFeed\";\n CharacterCodes[CharacterCodes[\"carriageReturn\"] = 13] = \"carriageReturn\";\n CharacterCodes[CharacterCodes[\"space\"] = 32] = \"space\";\n CharacterCodes[CharacterCodes[\"_0\"] = 48] = \"_0\";\n CharacterCodes[CharacterCodes[\"_1\"] = 49] = \"_1\";\n CharacterCodes[CharacterCodes[\"_2\"] = 50] = \"_2\";\n CharacterCodes[CharacterCodes[\"_3\"] = 51] = \"_3\";\n CharacterCodes[CharacterCodes[\"_4\"] = 52] = \"_4\";\n CharacterCodes[CharacterCodes[\"_5\"] = 53] = \"_5\";\n CharacterCodes[CharacterCodes[\"_6\"] = 54] = \"_6\";\n CharacterCodes[CharacterCodes[\"_7\"] = 55] = \"_7\";\n CharacterCodes[CharacterCodes[\"_8\"] = 56] = \"_8\";\n CharacterCodes[CharacterCodes[\"_9\"] = 57] = \"_9\";\n CharacterCodes[CharacterCodes[\"a\"] = 97] = \"a\";\n CharacterCodes[CharacterCodes[\"b\"] = 98] = \"b\";\n CharacterCodes[CharacterCodes[\"c\"] = 99] = \"c\";\n CharacterCodes[CharacterCodes[\"d\"] = 100] = \"d\";\n CharacterCodes[CharacterCodes[\"e\"] = 101] = \"e\";\n CharacterCodes[CharacterCodes[\"f\"] = 102] = \"f\";\n CharacterCodes[CharacterCodes[\"g\"] = 103] = \"g\";\n CharacterCodes[CharacterCodes[\"h\"] = 104] = \"h\";\n CharacterCodes[CharacterCodes[\"i\"] = 105] = \"i\";\n CharacterCodes[CharacterCodes[\"j\"] = 106] = \"j\";\n CharacterCodes[CharacterCodes[\"k\"] = 107] = \"k\";\n CharacterCodes[CharacterCodes[\"l\"] = 108] = \"l\";\n CharacterCodes[CharacterCodes[\"m\"] = 109] = \"m\";\n CharacterCodes[CharacterCodes[\"n\"] = 110] = \"n\";\n CharacterCodes[CharacterCodes[\"o\"] = 111] = \"o\";\n CharacterCodes[CharacterCodes[\"p\"] = 112] = \"p\";\n CharacterCodes[CharacterCodes[\"q\"] = 113] = \"q\";\n CharacterCodes[CharacterCodes[\"r\"] = 114] = \"r\";\n CharacterCodes[CharacterCodes[\"s\"] = 115] = \"s\";\n CharacterCodes[CharacterCodes[\"t\"] = 116] = \"t\";\n CharacterCodes[CharacterCodes[\"u\"] = 117] = \"u\";\n CharacterCodes[CharacterCodes[\"v\"] = 118] = \"v\";\n CharacterCodes[CharacterCodes[\"w\"] = 119] = \"w\";\n CharacterCodes[CharacterCodes[\"x\"] = 120] = \"x\";\n CharacterCodes[CharacterCodes[\"y\"] = 121] = \"y\";\n CharacterCodes[CharacterCodes[\"z\"] = 122] = \"z\";\n CharacterCodes[CharacterCodes[\"A\"] = 65] = \"A\";\n CharacterCodes[CharacterCodes[\"B\"] = 66] = \"B\";\n CharacterCodes[CharacterCodes[\"C\"] = 67] = \"C\";\n CharacterCodes[CharacterCodes[\"D\"] = 68] = \"D\";\n CharacterCodes[CharacterCodes[\"E\"] = 69] = \"E\";\n CharacterCodes[CharacterCodes[\"F\"] = 70] = \"F\";\n CharacterCodes[CharacterCodes[\"G\"] = 71] = \"G\";\n CharacterCodes[CharacterCodes[\"H\"] = 72] = \"H\";\n CharacterCodes[CharacterCodes[\"I\"] = 73] = \"I\";\n CharacterCodes[CharacterCodes[\"J\"] = 74] = \"J\";\n CharacterCodes[CharacterCodes[\"K\"] = 75] = \"K\";\n CharacterCodes[CharacterCodes[\"L\"] = 76] = \"L\";\n CharacterCodes[CharacterCodes[\"M\"] = 77] = \"M\";\n CharacterCodes[CharacterCodes[\"N\"] = 78] = \"N\";\n CharacterCodes[CharacterCodes[\"O\"] = 79] = \"O\";\n CharacterCodes[CharacterCodes[\"P\"] = 80] = \"P\";\n CharacterCodes[CharacterCodes[\"Q\"] = 81] = \"Q\";\n CharacterCodes[CharacterCodes[\"R\"] = 82] = \"R\";\n CharacterCodes[CharacterCodes[\"S\"] = 83] = \"S\";\n CharacterCodes[CharacterCodes[\"T\"] = 84] = \"T\";\n CharacterCodes[CharacterCodes[\"U\"] = 85] = \"U\";\n CharacterCodes[CharacterCodes[\"V\"] = 86] = \"V\";\n CharacterCodes[CharacterCodes[\"W\"] = 87] = \"W\";\n CharacterCodes[CharacterCodes[\"X\"] = 88] = \"X\";\n CharacterCodes[CharacterCodes[\"Y\"] = 89] = \"Y\";\n CharacterCodes[CharacterCodes[\"Z\"] = 90] = \"Z\";\n CharacterCodes[CharacterCodes[\"asterisk\"] = 42] = \"asterisk\";\n CharacterCodes[CharacterCodes[\"backslash\"] = 92] = \"backslash\";\n CharacterCodes[CharacterCodes[\"closeBrace\"] = 125] = \"closeBrace\";\n CharacterCodes[CharacterCodes[\"closeBracket\"] = 93] = \"closeBracket\";\n CharacterCodes[CharacterCodes[\"colon\"] = 58] = \"colon\";\n CharacterCodes[CharacterCodes[\"comma\"] = 44] = \"comma\";\n CharacterCodes[CharacterCodes[\"dot\"] = 46] = \"dot\";\n CharacterCodes[CharacterCodes[\"doubleQuote\"] = 34] = \"doubleQuote\";\n CharacterCodes[CharacterCodes[\"minus\"] = 45] = \"minus\";\n CharacterCodes[CharacterCodes[\"openBrace\"] = 123] = \"openBrace\";\n CharacterCodes[CharacterCodes[\"openBracket\"] = 91] = \"openBracket\";\n CharacterCodes[CharacterCodes[\"plus\"] = 43] = \"plus\";\n CharacterCodes[CharacterCodes[\"slash\"] = 47] = \"slash\";\n CharacterCodes[CharacterCodes[\"formFeed\"] = 12] = \"formFeed\";\n CharacterCodes[CharacterCodes[\"tab\"] = 9] = \"tab\";\n})(CharacterCodes || (CharacterCodes = {}));\n","export const cachedSpaces = new Array(20).fill(0).map((_, index) => {\n return ' '.repeat(index);\n});\nconst maxCachedValues = 200;\nexport const cachedBreakLinesWithSpaces = {\n ' ': {\n '\\n': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\n' + ' '.repeat(index);\n }),\n '\\r': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\r' + ' '.repeat(index);\n }),\n '\\r\\n': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\r\\n' + ' '.repeat(index);\n }),\n },\n '\\t': {\n '\\n': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\n' + '\\t'.repeat(index);\n }),\n '\\r': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\r' + '\\t'.repeat(index);\n }),\n '\\r\\n': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\r\\n' + '\\t'.repeat(index);\n }),\n }\n};\nexport const supportedEols = ['\\n', '\\r', '\\r\\n'];\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n'use strict';\nimport { createScanner } from './scanner';\nvar ParseOptions;\n(function (ParseOptions) {\n ParseOptions.DEFAULT = {\n allowTrailingComma: false\n };\n})(ParseOptions || (ParseOptions = {}));\n/**\n * For a given offset, evaluate the location in the JSON document. Each segment in the location path is either a property name or an array index.\n */\nexport function getLocation(text, position) {\n const segments = []; // strings or numbers\n const earlyReturnException = new Object();\n let previousNode = undefined;\n const previousNodeInst = {\n value: {},\n offset: 0,\n length: 0,\n type: 'object',\n parent: undefined\n };\n let isAtPropertyKey = false;\n function setPreviousNode(value, offset, length, type) {\n previousNodeInst.value = value;\n previousNodeInst.offset = offset;\n previousNodeInst.length = length;\n previousNodeInst.type = type;\n previousNodeInst.colonOffset = undefined;\n previousNode = previousNodeInst;\n }\n try {\n visit(text, {\n onObjectBegin: (offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n previousNode = undefined;\n isAtPropertyKey = position > offset;\n segments.push(''); // push a placeholder (will be replaced)\n },\n onObjectProperty: (name, offset, length) => {\n if (position < offset) {\n throw earlyReturnException;\n }\n setPreviousNode(name, offset, length, 'property');\n segments[segments.length - 1] = name;\n if (position <= offset + length) {\n throw earlyReturnException;\n }\n },\n onObjectEnd: (offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n previousNode = undefined;\n segments.pop();\n },\n onArrayBegin: (offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n previousNode = undefined;\n segments.push(0);\n },\n onArrayEnd: (offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n previousNode = undefined;\n segments.pop();\n },\n onLiteralValue: (value, offset, length) => {\n if (position < offset) {\n throw earlyReturnException;\n }\n setPreviousNode(value, offset, length, getNodeType(value));\n if (position <= offset + length) {\n throw earlyReturnException;\n }\n },\n onSeparator: (sep, offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n if (sep === ':' && previousNode && previousNode.type === 'property') {\n previousNode.colonOffset = offset;\n isAtPropertyKey = false;\n previousNode = undefined;\n }\n else if (sep === ',') {\n const last = segments[segments.length - 1];\n if (typeof last === 'number') {\n segments[segments.length - 1] = last + 1;\n }\n else {\n isAtPropertyKey = true;\n segments[segments.length - 1] = '';\n }\n previousNode = undefined;\n }\n }\n });\n }\n catch (e) {\n if (e !== earlyReturnException) {\n throw e;\n }\n }\n return {\n path: segments,\n previousNode,\n isAtPropertyKey,\n matches: (pattern) => {\n let k = 0;\n for (let i = 0; k < pattern.length && i < segments.length; i++) {\n if (pattern[k] === segments[i] || pattern[k] === '*') {\n k++;\n }\n else if (pattern[k] !== '**') {\n return false;\n }\n }\n return k === pattern.length;\n }\n };\n}\n/**\n * Parses the given text and returns the object the JSON content represents. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.\n * Therefore always check the errors list to find out if the input was valid.\n */\nexport function parse(text, errors = [], options = ParseOptions.DEFAULT) {\n let currentProperty = null;\n let currentParent = [];\n const previousParents = [];\n function onValue(value) {\n if (Array.isArray(currentParent)) {\n currentParent.push(value);\n }\n else if (currentProperty !== null) {\n currentParent[currentProperty] = value;\n }\n }\n const visitor = {\n onObjectBegin: () => {\n const object = {};\n onValue(object);\n previousParents.push(currentParent);\n currentParent = object;\n currentProperty = null;\n },\n onObjectProperty: (name) => {\n currentProperty = name;\n },\n onObjectEnd: () => {\n currentParent = previousParents.pop();\n },\n onArrayBegin: () => {\n const array = [];\n onValue(array);\n previousParents.push(currentParent);\n currentParent = array;\n currentProperty = null;\n },\n onArrayEnd: () => {\n currentParent = previousParents.pop();\n },\n onLiteralValue: onValue,\n onError: (error, offset, length) => {\n errors.push({ error, offset, length });\n }\n };\n visit(text, visitor, options);\n return currentParent[0];\n}\n/**\n * Parses the given text and returns a tree representation the JSON content. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.\n */\nexport function parseTree(text, errors = [], options = ParseOptions.DEFAULT) {\n let currentParent = { type: 'array', offset: -1, length: -1, children: [], parent: undefined }; // artificial root\n function ensurePropertyComplete(endOffset) {\n if (currentParent.type === 'property') {\n currentParent.length = endOffset - currentParent.offset;\n currentParent = currentParent.parent;\n }\n }\n function onValue(valueNode) {\n currentParent.children.push(valueNode);\n return valueNode;\n }\n const visitor = {\n onObjectBegin: (offset) => {\n currentParent = onValue({ type: 'object', offset, length: -1, parent: currentParent, children: [] });\n },\n onObjectProperty: (name, offset, length) => {\n currentParent = onValue({ type: 'property', offset, length: -1, parent: currentParent, children: [] });\n currentParent.children.push({ type: 'string', value: name, offset, length, parent: currentParent });\n },\n onObjectEnd: (offset, length) => {\n ensurePropertyComplete(offset + length); // in case of a missing value for a property: make sure property is complete\n currentParent.length = offset + length - currentParent.offset;\n currentParent = currentParent.parent;\n ensurePropertyComplete(offset + length);\n },\n onArrayBegin: (offset, length) => {\n currentParent = onValue({ type: 'array', offset, length: -1, parent: currentParent, children: [] });\n },\n onArrayEnd: (offset, length) => {\n currentParent.length = offset + length - currentParent.offset;\n currentParent = currentParent.parent;\n ensurePropertyComplete(offset + length);\n },\n onLiteralValue: (value, offset, length) => {\n onValue({ type: getNodeType(value), offset, length, parent: currentParent, value });\n ensurePropertyComplete(offset + length);\n },\n onSeparator: (sep, offset, length) => {\n if (currentParent.type === 'property') {\n if (sep === ':') {\n currentParent.colonOffset = offset;\n }\n else if (sep === ',') {\n ensurePropertyComplete(offset);\n }\n }\n },\n onError: (error, offset, length) => {\n errors.push({ error, offset, length });\n }\n };\n visit(text, visitor, options);\n const result = currentParent.children[0];\n if (result) {\n delete result.parent;\n }\n return result;\n}\n/**\n * Finds the node at the given path in a JSON DOM.\n */\nexport function findNodeAtLocation(root, path) {\n if (!root) {\n return undefined;\n }\n let node = root;\n for (let segment of path) {\n if (typeof segment === 'string') {\n if (node.type !== 'object' || !Array.isArray(node.children)) {\n return undefined;\n }\n let found = false;\n for (const propertyNode of node.children) {\n if (Array.isArray(propertyNode.children) && propertyNode.children[0].value === segment && propertyNode.children.length === 2) {\n node = propertyNode.children[1];\n found = true;\n break;\n }\n }\n if (!found) {\n return undefined;\n }\n }\n else {\n const index = segment;\n if (node.type !== 'array' || index < 0 || !Array.isArray(node.children) || index >= node.children.length) {\n return undefined;\n }\n node = node.children[index];\n }\n }\n return node;\n}\n/**\n * Gets the JSON path of the given JSON DOM node\n */\nexport function getNodePath(node) {\n if (!node.parent || !node.parent.children) {\n return [];\n }\n const path = getNodePath(node.parent);\n if (node.parent.type === 'property') {\n const key = node.parent.children[0].value;\n path.push(key);\n }\n else if (node.parent.type === 'array') {\n const index = node.parent.children.indexOf(node);\n if (index !== -1) {\n path.push(index);\n }\n }\n return path;\n}\n/**\n * Evaluates the JavaScript object of the given JSON DOM node\n */\nexport function getNodeValue(node) {\n switch (node.type) {\n case 'array':\n return node.children.map(getNodeValue);\n case 'object':\n const obj = Object.create(null);\n for (let prop of node.children) {\n const valueNode = prop.children[1];\n if (valueNode) {\n obj[prop.children[0].value] = getNodeValue(valueNode);\n }\n }\n return obj;\n case 'null':\n case 'string':\n case 'number':\n case 'boolean':\n return node.value;\n default:\n return undefined;\n }\n}\nexport function contains(node, offset, includeRightBound = false) {\n return (offset >= node.offset && offset < (node.offset + node.length)) || includeRightBound && (offset === (node.offset + node.length));\n}\n/**\n * Finds the most inner node at the given offset. If includeRightBound is set, also finds nodes that end at the given offset.\n */\nexport function findNodeAtOffset(node, offset, includeRightBound = false) {\n if (contains(node, offset, includeRightBound)) {\n const children = node.children;\n if (Array.isArray(children)) {\n for (let i = 0; i < children.length && children[i].offset <= offset; i++) {\n const item = findNodeAtOffset(children[i], offset, includeRightBound);\n if (item) {\n return item;\n }\n }\n }\n return node;\n }\n return undefined;\n}\n/**\n * Parses the given text and invokes the visitor functions for each object, array and literal reached.\n */\nexport function visit(text, visitor, options = ParseOptions.DEFAULT) {\n const _scanner = createScanner(text, false);\n // Important: Only pass copies of this to visitor functions to prevent accidental modification, and\n // to not affect visitor functions which stored a reference to a previous JSONPath\n const _jsonPath = [];\n // Depth of onXXXBegin() callbacks suppressed. onXXXEnd() decrements this if it isn't 0 already.\n // Callbacks are only called when this value is 0.\n let suppressedCallbacks = 0;\n function toNoArgVisit(visitFunction) {\n return visitFunction ? () => suppressedCallbacks === 0 && visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;\n }\n function toOneArgVisit(visitFunction) {\n return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;\n }\n function toOneArgVisitWithPath(visitFunction) {\n return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice()) : () => true;\n }\n function toBeginVisit(visitFunction) {\n return visitFunction ?\n () => {\n if (suppressedCallbacks > 0) {\n suppressedCallbacks++;\n }\n else {\n let cbReturn = visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice());\n if (cbReturn === false) {\n suppressedCallbacks = 1;\n }\n }\n }\n : () => true;\n }\n function toEndVisit(visitFunction) {\n return visitFunction ?\n () => {\n if (suppressedCallbacks > 0) {\n suppressedCallbacks--;\n }\n if (suppressedCallbacks === 0) {\n visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter());\n }\n }\n : () => true;\n }\n const onObjectBegin = toBeginVisit(visitor.onObjectBegin), onObjectProperty = toOneArgVisitWithPath(visitor.onObjectProperty), onObjectEnd = toEndVisit(visitor.onObjectEnd), onArrayBegin = toBeginVisit(visitor.onArrayBegin), onArrayEnd = toEndVisit(visitor.onArrayEnd), onLiteralValue = toOneArgVisitWithPath(visitor.onLiteralValue), onSeparator = toOneArgVisit(visitor.onSeparator), onComment = toNoArgVisit(visitor.onComment), onError = toOneArgVisit(visitor.onError);\n const disallowComments = options && options.disallowComments;\n const allowTrailingComma = options && options.allowTrailingComma;\n function scanNext() {\n while (true) {\n const token = _scanner.scan();\n switch (_scanner.getTokenError()) {\n case 4 /* ScanError.InvalidUnicode */:\n handleError(14 /* ParseErrorCode.InvalidUnicode */);\n break;\n case 5 /* ScanError.InvalidEscapeCharacter */:\n handleError(15 /* ParseErrorCode.InvalidEscapeCharacter */);\n break;\n case 3 /* ScanError.UnexpectedEndOfNumber */:\n handleError(13 /* ParseErrorCode.UnexpectedEndOfNumber */);\n break;\n case 1 /* ScanError.UnexpectedEndOfComment */:\n if (!disallowComments) {\n handleError(11 /* ParseErrorCode.UnexpectedEndOfComment */);\n }\n break;\n case 2 /* ScanError.UnexpectedEndOfString */:\n handleError(12 /* ParseErrorCode.UnexpectedEndOfString */);\n break;\n case 6 /* ScanError.InvalidCharacter */:\n handleError(16 /* ParseErrorCode.InvalidCharacter */);\n break;\n }\n switch (token) {\n case 12 /* SyntaxKind.LineCommentTrivia */:\n case 13 /* SyntaxKind.BlockCommentTrivia */:\n if (disallowComments) {\n handleError(10 /* ParseErrorCode.InvalidCommentToken */);\n }\n else {\n onComment();\n }\n break;\n case 16 /* SyntaxKind.Unknown */:\n handleError(1 /* ParseErrorCode.InvalidSymbol */);\n break;\n case 15 /* SyntaxKind.Trivia */:\n case 14 /* SyntaxKind.LineBreakTrivia */:\n break;\n default:\n return token;\n }\n }\n }\n function handleError(error, skipUntilAfter = [], skipUntil = []) {\n onError(error);\n if (skipUntilAfter.length + skipUntil.length > 0) {\n let token = _scanner.getToken();\n while (token !== 17 /* SyntaxKind.EOF */) {\n if (skipUntilAfter.indexOf(token) !== -1) {\n scanNext();\n break;\n }\n else if (skipUntil.indexOf(token) !== -1) {\n break;\n }\n token = scanNext();\n }\n }\n }\n function parseString(isValue) {\n const value = _scanner.getTokenValue();\n if (isValue) {\n onLiteralValue(value);\n }\n else {\n onObjectProperty(value);\n // add property name afterwards\n _jsonPath.push(value);\n }\n scanNext();\n return true;\n }\n function parseLiteral() {\n switch (_scanner.getToken()) {\n case 11 /* SyntaxKind.NumericLiteral */:\n const tokenValue = _scanner.getTokenValue();\n let value = Number(tokenValue);\n if (isNaN(value)) {\n handleError(2 /* ParseErrorCode.InvalidNumberFormat */);\n value = 0;\n }\n onLiteralValue(value);\n break;\n case 7 /* SyntaxKind.NullKeyword */:\n onLiteralValue(null);\n break;\n case 8 /* SyntaxKind.TrueKeyword */:\n onLiteralValue(true);\n break;\n case 9 /* SyntaxKind.FalseKeyword */:\n onLiteralValue(false);\n break;\n default:\n return false;\n }\n scanNext();\n return true;\n }\n function parseProperty() {\n if (_scanner.getToken() !== 10 /* SyntaxKind.StringLiteral */) {\n handleError(3 /* ParseErrorCode.PropertyNameExpected */, [], [2 /* SyntaxKind.CloseBraceToken */, 5 /* SyntaxKind.CommaToken */]);\n return false;\n }\n parseString(false);\n if (_scanner.getToken() === 6 /* SyntaxKind.ColonToken */) {\n onSeparator(':');\n scanNext(); // consume colon\n if (!parseValue()) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], [2 /* SyntaxKind.CloseBraceToken */, 5 /* SyntaxKind.CommaToken */]);\n }\n }\n else {\n handleError(5 /* ParseErrorCode.ColonExpected */, [], [2 /* SyntaxKind.CloseBraceToken */, 5 /* SyntaxKind.CommaToken */]);\n }\n _jsonPath.pop(); // remove processed property name\n return true;\n }\n function parseObject() {\n onObjectBegin();\n scanNext(); // consume open brace\n let needsComma = false;\n while (_scanner.getToken() !== 2 /* SyntaxKind.CloseBraceToken */ && _scanner.getToken() !== 17 /* SyntaxKind.EOF */) {\n if (_scanner.getToken() === 5 /* SyntaxKind.CommaToken */) {\n if (!needsComma) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], []);\n }\n onSeparator(',');\n scanNext(); // consume comma\n if (_scanner.getToken() === 2 /* SyntaxKind.CloseBraceToken */ && allowTrailingComma) {\n break;\n }\n }\n else if (needsComma) {\n handleError(6 /* ParseErrorCode.CommaExpected */, [], []);\n }\n if (!parseProperty()) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], [2 /* SyntaxKind.CloseBraceToken */, 5 /* SyntaxKind.CommaToken */]);\n }\n needsComma = true;\n }\n onObjectEnd();\n if (_scanner.getToken() !== 2 /* SyntaxKind.CloseBraceToken */) {\n handleError(7 /* ParseErrorCode.CloseBraceExpected */, [2 /* SyntaxKind.CloseBraceToken */], []);\n }\n else {\n scanNext(); // consume close brace\n }\n return true;\n }\n function parseArray() {\n onArrayBegin();\n scanNext(); // consume open bracket\n let isFirstElement = true;\n let needsComma = false;\n while (_scanner.getToken() !== 4 /* SyntaxKind.CloseBracketToken */ && _scanner.getToken() !== 17 /* SyntaxKind.EOF */) {\n if (_scanner.getToken() === 5 /* SyntaxKind.CommaToken */) {\n if (!needsComma) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], []);\n }\n onSeparator(',');\n scanNext(); // consume comma\n if (_scanner.getToken() === 4 /* SyntaxKind.CloseBracketToken */ && allowTrailingComma) {\n break;\n }\n }\n else if (needsComma) {\n handleError(6 /* ParseErrorCode.CommaExpected */, [], []);\n }\n if (isFirstElement) {\n _jsonPath.push(0);\n isFirstElement = false;\n }\n else {\n _jsonPath[_jsonPath.length - 1]++;\n }\n if (!parseValue()) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], [4 /* SyntaxKind.CloseBracketToken */, 5 /* SyntaxKind.CommaToken */]);\n }\n needsComma = true;\n }\n onArrayEnd();\n if (!isFirstElement) {\n _jsonPath.pop(); // remove array index\n }\n if (_scanner.getToken() !== 4 /* SyntaxKind.CloseBracketToken */) {\n handleError(8 /* ParseErrorCode.CloseBracketExpected */, [4 /* SyntaxKind.CloseBracketToken */], []);\n }\n else {\n scanNext(); // consume close bracket\n }\n return true;\n }\n function parseValue() {\n switch (_scanner.getToken()) {\n case 3 /* SyntaxKind.OpenBracketToken */:\n return parseArray();\n case 1 /* SyntaxKind.OpenBraceToken */:\n return parseObject();\n case 10 /* SyntaxKind.StringLiteral */:\n return parseString(true);\n default:\n return parseLiteral();\n }\n }\n scanNext();\n if (_scanner.getToken() === 17 /* SyntaxKind.EOF */) {\n if (options.allowEmptyContent) {\n return true;\n }\n handleError(4 /* ParseErrorCode.ValueExpected */, [], []);\n return false;\n }\n if (!parseValue()) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], []);\n return false;\n }\n if (_scanner.getToken() !== 17 /* SyntaxKind.EOF */) {\n handleError(9 /* ParseErrorCode.EndOfFileExpected */, [], []);\n }\n return true;\n}\n/**\n * Takes JSON with JavaScript-style comments and remove\n * them. Optionally replaces every none-newline character\n * of comments with a replaceCharacter\n */\nexport function stripComments(text, replaceCh) {\n let _scanner = createScanner(text), parts = [], kind, offset = 0, pos;\n do {\n pos = _scanner.getPosition();\n kind = _scanner.scan();\n switch (kind) {\n case 12 /* SyntaxKind.LineCommentTrivia */:\n case 13 /* SyntaxKind.BlockCommentTrivia */:\n case 17 /* SyntaxKind.EOF */:\n if (offset !== pos) {\n parts.push(text.substring(offset, pos));\n }\n if (replaceCh !== undefined) {\n parts.push(_scanner.getTokenValue().replace(/[^\\r\\n]/g, replaceCh));\n }\n offset = _scanner.getPosition();\n break;\n }\n } while (kind !== 17 /* SyntaxKind.EOF */);\n return parts.join('');\n}\nexport function getNodeType(value) {\n switch (typeof value) {\n case 'boolean': return 'boolean';\n case 'number': return 'number';\n case 'string': return 'string';\n case 'object': {\n if (!value) {\n return 'null';\n }\n else if (Array.isArray(value)) {\n return 'array';\n }\n return 'object';\n }\n default: return 'null';\n }\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n'use strict';\nimport * as formatter from './impl/format';\nimport * as edit from './impl/edit';\nimport * as scanner from './impl/scanner';\nimport * as parser from './impl/parser';\n/**\n * Creates a JSON scanner on the given text.\n * If ignoreTrivia is set, whitespaces or comments are ignored.\n */\nexport const createScanner = scanner.createScanner;\nexport var ScanError;\n(function (ScanError) {\n ScanError[ScanError[\"None\"] = 0] = \"None\";\n ScanError[ScanError[\"UnexpectedEndOfComment\"] = 1] = \"UnexpectedEndOfComment\";\n ScanError[ScanError[\"UnexpectedEndOfString\"] = 2] = \"UnexpectedEndOfString\";\n ScanError[ScanError[\"UnexpectedEndOfNumber\"] = 3] = \"UnexpectedEndOfNumber\";\n ScanError[ScanError[\"InvalidUnicode\"] = 4] = \"InvalidUnicode\";\n ScanError[ScanError[\"InvalidEscapeCharacter\"] = 5] = \"InvalidEscapeCharacter\";\n ScanError[ScanError[\"InvalidCharacter\"] = 6] = \"InvalidCharacter\";\n})(ScanError || (ScanError = {}));\nexport var SyntaxKind;\n(function (SyntaxKind) {\n SyntaxKind[SyntaxKind[\"OpenBraceToken\"] = 1] = \"OpenBraceToken\";\n SyntaxKind[SyntaxKind[\"CloseBraceToken\"] = 2] = \"CloseBraceToken\";\n SyntaxKind[SyntaxKind[\"OpenBracketToken\"] = 3] = \"OpenBracketToken\";\n SyntaxKind[SyntaxKind[\"CloseBracketToken\"] = 4] = \"CloseBracketToken\";\n SyntaxKind[SyntaxKind[\"CommaToken\"] = 5] = \"CommaToken\";\n SyntaxKind[SyntaxKind[\"ColonToken\"] = 6] = \"ColonToken\";\n SyntaxKind[SyntaxKind[\"NullKeyword\"] = 7] = \"NullKeyword\";\n SyntaxKind[SyntaxKind[\"TrueKeyword\"] = 8] = \"TrueKeyword\";\n SyntaxKind[SyntaxKind[\"FalseKeyword\"] = 9] = \"FalseKeyword\";\n SyntaxKind[SyntaxKind[\"StringLiteral\"] = 10] = \"StringLiteral\";\n SyntaxKind[SyntaxKind[\"NumericLiteral\"] = 11] = \"NumericLiteral\";\n SyntaxKind[SyntaxKind[\"LineCommentTrivia\"] = 12] = \"LineCommentTrivia\";\n SyntaxKind[SyntaxKind[\"BlockCommentTrivia\"] = 13] = \"BlockCommentTrivia\";\n SyntaxKind[SyntaxKind[\"LineBreakTrivia\"] = 14] = \"LineBreakTrivia\";\n SyntaxKind[SyntaxKind[\"Trivia\"] = 15] = \"Trivia\";\n SyntaxKind[SyntaxKind[\"Unknown\"] = 16] = \"Unknown\";\n SyntaxKind[SyntaxKind[\"EOF\"] = 17] = \"EOF\";\n})(SyntaxKind || (SyntaxKind = {}));\n/**\n * For a given offset, evaluate the location in the JSON document. Each segment in the location path is either a property name or an array index.\n */\nexport const getLocation = parser.getLocation;\n/**\n * Parses the given text and returns the object the JSON content represents. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.\n * Therefore, always check the errors list to find out if the input was valid.\n */\nexport const parse = parser.parse;\n/**\n * Parses the given text and returns a tree representation the JSON content. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.\n */\nexport const parseTree = parser.parseTree;\n/**\n * Finds the node at the given path in a JSON DOM.\n */\nexport const findNodeAtLocation = parser.findNodeAtLocation;\n/**\n * Finds the innermost node at the given offset. If includeRightBound is set, also finds nodes that end at the given offset.\n */\nexport const findNodeAtOffset = parser.findNodeAtOffset;\n/**\n * Gets the JSON path of the given JSON DOM node\n */\nexport const getNodePath = parser.getNodePath;\n/**\n * Evaluates the JavaScript object of the given JSON DOM node\n */\nexport const getNodeValue = parser.getNodeValue;\n/**\n * Parses the given text and invokes the visitor functions for each object, array and literal reached.\n */\nexport const visit = parser.visit;\n/**\n * Takes JSON with JavaScript-style comments and remove\n * them. Optionally replaces every none-newline character\n * of comments with a replaceCharacter\n */\nexport const stripComments = parser.stripComments;\nexport var ParseErrorCode;\n(function (ParseErrorCode) {\n ParseErrorCode[ParseErrorCode[\"InvalidSymbol\"] = 1] = \"InvalidSymbol\";\n ParseErrorCode[ParseErrorCode[\"InvalidNumberFormat\"] = 2] = \"InvalidNumberFormat\";\n ParseErrorCode[ParseErrorCode[\"PropertyNameExpected\"] = 3] = \"PropertyNameExpected\";\n ParseErrorCode[ParseErrorCode[\"ValueExpected\"] = 4] = \"ValueExpected\";\n ParseErrorCode[ParseErrorCode[\"ColonExpected\"] = 5] = \"ColonExpected\";\n ParseErrorCode[ParseErrorCode[\"CommaExpected\"] = 6] = \"CommaExpected\";\n ParseErrorCode[ParseErrorCode[\"CloseBraceExpected\"] = 7] = \"CloseBraceExpected\";\n ParseErrorCode[ParseErrorCode[\"CloseBracketExpected\"] = 8] = \"CloseBracketExpected\";\n ParseErrorCode[ParseErrorCode[\"EndOfFileExpected\"] = 9] = \"EndOfFileExpected\";\n ParseErrorCode[ParseErrorCode[\"InvalidCommentToken\"] = 10] = \"InvalidCommentToken\";\n ParseErrorCode[ParseErrorCode[\"UnexpectedEndOfComment\"] = 11] = \"UnexpectedEndOfComment\";\n ParseErrorCode[ParseErrorCode[\"UnexpectedEndOfString\"] = 12] = \"UnexpectedEndOfString\";\n ParseErrorCode[ParseErrorCode[\"UnexpectedEndOfNumber\"] = 13] = \"UnexpectedEndOfNumber\";\n ParseErrorCode[ParseErrorCode[\"InvalidUnicode\"] = 14] = \"InvalidUnicode\";\n ParseErrorCode[ParseErrorCode[\"InvalidEscapeCharacter\"] = 15] = \"InvalidEscapeCharacter\";\n ParseErrorCode[ParseErrorCode[\"InvalidCharacter\"] = 16] = \"InvalidCharacter\";\n})(ParseErrorCode || (ParseErrorCode = {}));\nexport function printParseErrorCode(code) {\n switch (code) {\n case 1 /* ParseErrorCode.InvalidSymbol */: return 'InvalidSymbol';\n case 2 /* ParseErrorCode.InvalidNumberFormat */: return 'InvalidNumberFormat';\n case 3 /* ParseErrorCode.PropertyNameExpected */: return 'PropertyNameExpected';\n case 4 /* ParseErrorCode.ValueExpected */: return 'ValueExpected';\n case 5 /* ParseErrorCode.ColonExpected */: return 'ColonExpected';\n case 6 /* ParseErrorCode.CommaExpected */: return 'CommaExpected';\n case 7 /* ParseErrorCode.CloseBraceExpected */: return 'CloseBraceExpected';\n case 8 /* ParseErrorCode.CloseBracketExpected */: return 'CloseBracketExpected';\n case 9 /* ParseErrorCode.EndOfFileExpected */: return 'EndOfFileExpected';\n case 10 /* ParseErrorCode.InvalidCommentToken */: return 'InvalidCommentToken';\n case 11 /* ParseErrorCode.UnexpectedEndOfComment */: return 'UnexpectedEndOfComment';\n case 12 /* ParseErrorCode.UnexpectedEndOfString */: return 'UnexpectedEndOfString';\n case 13 /* ParseErrorCode.UnexpectedEndOfNumber */: return 'UnexpectedEndOfNumber';\n case 14 /* ParseErrorCode.InvalidUnicode */: return 'InvalidUnicode';\n case 15 /* ParseErrorCode.InvalidEscapeCharacter */: return 'InvalidEscapeCharacter';\n case 16 /* ParseErrorCode.InvalidCharacter */: return 'InvalidCharacter';\n }\n return '<unknown ParseErrorCode>';\n}\n/**\n * Computes the edit operations needed to format a JSON document.\n *\n * @param documentText The input text\n * @param range The range to format or `undefined` to format the full content\n * @param options The formatting options\n * @returns The edit operations describing the formatting changes to the original document following the format described in {@linkcode EditResult}.\n * To apply the edit operations to the input, use {@linkcode applyEdits}.\n */\nexport function format(documentText, range, options) {\n return formatter.format(documentText, range, options);\n}\n/**\n * Computes the edit operations needed to modify a value in the JSON document.\n *\n * @param documentText The input text\n * @param path The path of the value to change. The path represents either to the document root, a property or an array item.\n * If the path points to an non-existing property or item, it will be created.\n * @param value The new value for the specified property or item. If the value is undefined,\n * the property or item will be removed.\n * @param options Options\n * @returns The edit operations describing the changes to the original document, following the format described in {@linkcode EditResult}.\n * To apply the edit operations to the input, use {@linkcode applyEdits}.\n */\nexport function modify(text, path, value, options) {\n return edit.setProperty(text, path, value, options);\n}\n/**\n * Applies edits to an input string.\n * @param text The input text\n * @param edits Edit operations following the format described in {@linkcode EditResult}.\n * @returns The text with the applied edits.\n * @throws An error if the edit operations are not well-formed as described in {@linkcode EditResult}.\n */\nexport function applyEdits(text, edits) {\n let sortedEdits = edits.slice(0).sort((a, b) => {\n const diff = a.offset - b.offset;\n if (diff === 0) {\n return a.length - b.length;\n }\n return diff;\n });\n let lastModifiedOffset = text.length;\n for (let i = sortedEdits.length - 1; i >= 0; i--) {\n let e = sortedEdits[i];\n if (e.offset + e.length <= lastModifiedOffset) {\n text = edit.applyEdit(text, e);\n }\n else {\n throw new Error('Overlapping edit');\n }\n lastModifiedOffset = e.offset;\n }\n return text;\n}\n","import { beacon } from \"./client\";\nimport { DWELL_THRESHOLD_MS } from \"./constants\";\nimport { debugLog } from \"./debug\";\nimport { adCachePath, pendingTurnPath, terminalHeartbeatPath } from \"./paths\";\nimport { readJson, writeJsonAtomic } from \"./store\";\nimport type {\n\tTAd,\n\tTAdCache,\n\tTCachedAd,\n\tTCachedAdSet,\n\tTPendingTurn,\n} from \"./types\";\n\n/**\n * How stale a terminal heartbeat can be and still count as \"a real terminal\n * is active right now\". Claude Code re-invokes `statusLine` roughly every\n * 300ms while a real terminal is actually rendering it, so anything within\n * a few seconds is a live terminal; anything older means no terminal has\n * rendered recently, so this hook invocation almost certainly belongs to the\n * IDE chat panel instead (the only other supported surface, and one that\n * never touches this file at all).\n */\nconst _TERMINAL_HEARTBEAT_STALE_MS = 5_000;\n\n/**\n * Guards every read of a cache entry against a shape this version doesn't\n * recognize -- treated exactly like \"no entry\" (`null`/no-op), never a\n * crash. `TCachedAdSet` replaced an older single-ad shape earlier this same\n * project; a machine whose `~/.kili/ad-cache.json` still has an entry from\n * before that (an old extension build that never got a chance to overwrite\n * it, a partially-written file, anything) has `entry.ads === undefined`,\n * and every function here used to reach straight for `entry.ads.length`\n * with nothing checking that first -- confirmed live: `TypeError: Cannot\n * read properties of undefined (reading 'length')` in `advanceRotation`,\n * crashing the extension host on a fresh install. `entry` is read as\n * `unknown` on purpose so this stays the one place that has to know what a\n * valid entry actually looks like.\n */\nfunction _isValidEntry(entry: unknown): entry is TCachedAdSet {\n\treturn (\n\t\ttypeof entry === \"object\" &&\n\t\tentry !== null &&\n\t\tArray.isArray((entry as TCachedAdSet).ads) &&\n\t\tArray.isArray((entry as TCachedAdSet).perAd) &&\n\t\ttypeof (entry as TCachedAdSet).currentIndex === \"number\"\n\t);\n}\n\n/** Called by `statusline.ts` on every invocation -- see `terminalHeartbeatPath`\n * and `isTerminalActive`. */\nexport function touchTerminalHeartbeat(): void {\n\twriteJsonAtomic(terminalHeartbeatPath(), { ts: Date.now() });\n}\n\n/**\n * Whether a real terminal is currently rendering `statusLine`, inferred from\n * how recently `statusline.ts` last ran. `hook.ts` uses this to decide which\n * *single* spinner placement a turn's impression belongs to -- terminal or\n * IDE chat panel, never both. Before this existed, every turn unconditionally\n * settled impressions for both `TERMINAL_SPINNER` and `EXTENSION_SPINNER`,\n * so a user looking at only one of the two surfaces was silently billed for\n * a \"view\" of the other one too, which nothing was ever rendering.\n */\nexport function isTerminalActive(): boolean {\n\tconst heartbeat = readJson<{ ts: number } | null>(\n\t\tterminalHeartbeatPath(),\n\t\tnull,\n\t);\n\tif (!heartbeat) return false;\n\treturn Date.now() - heartbeat.ts < _TERMINAL_HEARTBEAT_STALE_MS;\n}\n\n/**\n * Store a freshly-fetched rotation set for a placement, replacing whatever\n * was there. `api.kili` now serves every eligible ad to every requested\n * placement (see `ads.service.ts`'s `_serveSelectedAds`), so a placement\n * with a live process behind it can rotate through more than one ad across a\n * single long turn instead of showing one static ad the whole time. Starts\n * at `currentIndex: 0` -- the first ad in the (server-shuffled) list is\n * whatever's shown immediately, before any rotation tick has run.\n */\nexport function putAd(placementId: string, ads: TAd[]): TCachedAdSet {\n\tconst cache = readJson<TAdCache>(adCachePath(), {});\n\tconst entry: TCachedAdSet = {\n\t\tads,\n\t\tcurrentIndex: 0,\n\t\trotationStartedAt: Date.now(),\n\t\tperAd: ads.map(() => ({ firstSeenAt: null, impressionFiredAt: null })),\n\t};\n\tcache[placementId] = entry;\n\twriteJsonAtomic(adCachePath(), cache);\n\t// KILI_DEBUG=1 only -- a rotation set of size 1 means there's genuinely\n\t// nothing to rotate through this turn (only one eligible/relevant ad),\n\t// not a bug in the rotation timer itself. This is the fastest way to\n\t// tell \"rotation isn't firing\" apart from \"rotation has nothing to do\".\n\tdebugLog(\"putAd\", { placementId, adCount: ads.length });\n\treturn entry;\n}\n\n/** The currently-active ad for a placement, projected out of its rotation\n * set -- callers that only care about \"what's on screen right now\" (e.g.\n * `extension.ts`'s `Kili: Show Status`) never need to know rotation sets\n * exist at all. */\nexport function getAd(placementId: string): TCachedAd | null {\n\tconst cache = readJson<TAdCache>(adCachePath(), {});\n\tconst entry = cache[placementId];\n\tif (!_isValidEntry(entry) || entry.ads.length === 0) return null;\n\tconst dwell = entry.perAd[entry.currentIndex];\n\treturn {\n\t\tad: entry.ads[entry.currentIndex],\n\t\tfetchedAt: entry.rotationStartedAt,\n\t\tfirstSeenAt: dwell?.firstSeenAt ?? null,\n\t\timpressionFiredAt: dwell?.impressionFiredAt ?? null,\n\t};\n}\n\n/**\n * Called every time a directly-rendered, repeatedly-polled surface (the\n * terminal status line, invoked by Claude Code roughly every 300ms) actually\n * paints the *currently-active* ad in a placement's rotation set. Tracks\n * that one ad's own continuous dwell and fires `impUrl` exactly once, the\n * moment it's been visible for `DWELL_THRESHOLD_MS` -- never before, never\n * twice. Needs at least two calls to actually fire (first arms\n * `firstSeenAt`, a later one claims it) -- fine for a surface that's polled\n * every 300ms, but see `claimCurrentImpression` for a placement that isn't\n * (like the extension spinner rotation timer, which writes a new ad once\n * per interval rather than being polled).\n */\nexport async function markRenderedAndClaimImpression(\n\tplacementId: string,\n): Promise<void> {\n\tconst cache = readJson<TAdCache>(adCachePath(), {});\n\tconst entry = cache[placementId];\n\tif (!_isValidEntry(entry) || entry.ads.length === 0) return;\n\tconst dwell = entry.perAd[entry.currentIndex];\n\tif (!dwell || dwell.impressionFiredAt) return;\n\n\tconst now = Date.now();\n\tif (dwell.firstSeenAt === null) {\n\t\tdwell.firstSeenAt = now;\n\t\twriteJsonAtomic(adCachePath(), cache);\n\t\treturn;\n\t}\n\n\tif (now - dwell.firstSeenAt < DWELL_THRESHOLD_MS) return;\n\n\tdwell.impressionFiredAt = now;\n\twriteJsonAtomic(adCachePath(), cache);\n\tawait beacon(entry.ads[entry.currentIndex].impUrl);\n}\n\n/**\n * Immediately fires the impression for a placement's currently-active ad, if\n * not already fired -- for callers that write a new ad once and don't get a\n * natural second \"render tick\" to satisfy `markRenderedAndClaimImpression`'s\n * arm-then-fire pattern. `extension.ts`'s turn-start fetch is the one\n * caller: it fetches a fresh ad the moment a new turn begins and writes it\n * once, and that single write is the whole \"render\" this ad ever gets from\n * our side before the next turn replaces it. Safe given `DWELL_THRESHOLD_MS\n * = 0`: \"shown is enough\" (see that constant's doc comment) already means\n * there's no minimum dwell worth waiting out here, so firing on first sight\n * is exactly the documented policy, not a shortcut around it.\n */\nexport async function claimCurrentImpression(\n\tplacementId: string,\n): Promise<void> {\n\tconst cache = readJson<TAdCache>(adCachePath(), {});\n\tconst entry = cache[placementId];\n\tif (!_isValidEntry(entry) || entry.ads.length === 0) return;\n\tconst dwell = entry.perAd[entry.currentIndex];\n\tif (!dwell || dwell.impressionFiredAt) return;\n\n\tconst now = Date.now();\n\tdwell.impressionFiredAt = now;\n\tif (dwell.firstSeenAt === null) dwell.firstSeenAt = now;\n\twriteJsonAtomic(adCachePath(), cache);\n\tawait beacon(entry.ads[entry.currentIndex].impUrl);\n}\n\n/** Written by `UserPromptSubmit`, read (and cleared) by `Stop` -- the proxy\n * pair that infers a spinner-verb impression we can't directly observe. */\nexport function startPendingTurn(pending: TPendingTurn): void {\n\twriteJsonAtomic(pendingTurnPath(), pending);\n}\n\nexport function takePendingTurn(): TPendingTurn | null {\n\tconst pending = readJson<TPendingTurn | null>(pendingTurnPath(), null);\n\tif (pending) writeJsonAtomic(pendingTurnPath(), null);\n\treturn pending;\n}\n\n/**\n * Non-consuming check for whether a turn is currently in flight (started by\n * `UserPromptSubmit`, not yet settled by `Stop`). `extension.ts`'s periodic\n * refresh timer uses this to skip itself mid-turn: firing anyway would\n * overwrite `claudeCode.spinnerVerbs` with a newly-fetched, likely different\n * ad while the turn's spinner is still showing the one from turn start --\n * a visible ad swap partway through, with the first ad's impression never\n * getting a full dwell window and the second one starting its dwell clock\n * late. `hook.ts`'s own per-turn refresh already covers keeping the ad fresh\n * at each turn boundary, so skipping the idle timer mid-turn loses nothing.\n */\nexport function hasPendingTurn(): boolean {\n\treturn readJson<TPendingTurn | null>(pendingTurnPath(), null) !== null;\n}\n\n/**\n * Non-consuming read of the full pending-turn record, not just whether one\n * exists -- `extension.ts` uses `startedAt` here to tell \"still the same\n * turn I already fetched an ad for\" apart from \"a genuinely new turn just\n * started\", since this file gets polled repeatedly over a turn's lifetime,\n * not read once. Returns `null` exactly when `hasPendingTurn` would be\n * `false`.\n */\nexport function peekPendingTurn(): TPendingTurn | null {\n\treturn readJson<TPendingTurn | null>(pendingTurnPath(), null);\n}\n\n/**\n * `Stop`-side half: if the turn that just ended ran at least\n * `DWELL_THRESHOLD_MS` -- meaning the spinner, whatever it showed, was on\n * screen that whole time -- fire the impression for whichever ad is\n * *currently active* in each spinner-text placement's rotation set (terminal\n * spinner, extension sidebar spinner). A turn shorter than the threshold\n * means the spinner barely showed, so none of them qualify.\n *\n * The terminal spinner never rotates mid-turn (no persistent process behind\n * it to drive a timer -- see `extension.ts`'s rotation timer doc comment),\n * so this is its *only* impression trigger, same as before: one ad, one\n * impression, whole turn. The extension spinner *does* rotate, driven by\n * `extension.ts`'s timer, which already fires an impression per ad the\n * moment it's shown (`claimCurrentImpression`) -- this is just a\n * safety net for whatever's current when the turn actually ends, guarded by\n * the same `impressionFiredAt` check so it can never double-bill an ad the\n * rotation timer already claimed.\n */\nexport async function settlePendingTurn(): Promise<void> {\n\tconst pending = takePendingTurn();\n\tif (!pending) {\n\t\tdebugLog(\"settlePendingTurn: nothing pending\");\n\t\treturn;\n\t}\n\tconst dwellMs = Date.now() - pending.startedAt;\n\tif (dwellMs < DWELL_THRESHOLD_MS) {\n\t\tdebugLog(\"settlePendingTurn: turn too short\", {\n\t\t\tdwellMs,\n\t\t\tthreshold: DWELL_THRESHOLD_MS,\n\t\t});\n\t\treturn;\n\t}\n\n\tconst cache = readJson<TAdCache>(adCachePath(), {});\n\tlet changed = false;\n\tconst toBeacon: string[] = [];\n\tconst decisions: Record<string, string> = {};\n\tfor (const placementId of pending.placementIds) {\n\t\tconst entry = cache[placementId];\n\t\tif (!_isValidEntry(entry) || entry.ads.length === 0) {\n\t\t\tdecisions[placementId] = \"no cached rotation set\";\n\t\t\tcontinue;\n\t\t}\n\t\tconst dwell = entry.perAd[entry.currentIndex];\n\t\tif (!dwell || dwell.impressionFiredAt) {\n\t\t\tdecisions[placementId] = \"already fired\";\n\t\t\tcontinue;\n\t\t}\n\t\tdwell.impressionFiredAt = Date.now();\n\t\tchanged = true;\n\t\tconst impUrl = entry.ads[entry.currentIndex].impUrl;\n\t\tif (impUrl) toBeacon.push(impUrl);\n\t\tdecisions[placementId] = \"fired\";\n\t}\n\tdebugLog(\"settlePendingTurn\", {\n\t\tplacementIds: pending.placementIds,\n\t\tdwellMs,\n\t\tdecisions,\n\t});\n\tif (changed) writeJsonAtomic(adCachePath(), cache);\n\tawait Promise.all(toBeacon.map((url) => beacon(url)));\n}\n","import { randomUUID } from \"node:crypto\";\nimport { DEFAULT_API_URL, DEFAULT_WEB_URL } from \"./constants\";\nimport { runtimeConfigPath } from \"./paths\";\nimport { readJson, writeJsonAtomic } from \"./store\";\nimport type { TRuntimeConfig } from \"./types\";\n\n/**\n * `~/.kili/config.json` holds one thing: the extension's resolved config,\n * read back by `hook.ts` and `statusline.ts` (both spawned fresh per call,\n * neither able to read VS Code's own configuration API). `installId` lives\n * in the same file so it survives independently of whether a key has been\n * set yet -- `ensureInstallId` merges rather than overwrites so it never\n * clobbers a config the extension already wrote.\n *\n * `apiKey` survives an *implicit* re-sign-in (e.g. `npx @kili-ai/install`\n * run again on a device that already has one) -- that's what\n * `readRuntimeConfig`/`readCachedApiKey` short-circuiting is for, and it's\n * what keeps a non-interactive re-run from minting a duplicate key/surface\n * every time (see `pkg.install.kili/src/terminal.ts`'s doc comment: this\n * used to mint 37 near-duplicate surfaces for one account before that cache\n * existed).\n *\n * An *explicit* \"Kili: Sign Out\", though, clears it here too (see\n * `extension.ts`'s `_handleSignOut` -> `clearCachedApiKey`) -- signing out is\n * a deliberate action, not an accidental re-run, and the whole point of it is\n * to let the next sign-in be a real one: a different account, or a\n * deliberately fresh key for this one. The old key's plaintext is gone for\n * good either way (the server only ever stores a one-way hash -- see\n * `db/schema.ts`'s `publisherSurfaces.keyHash`), so there is no \"recover it\n * instead of minting a new one\" option here regardless.\n */\ntype TStoredConfig = Partial<TRuntimeConfig> & { installId?: string };\n\nfunction _read(): TStoredConfig {\n\treturn readJson<TStoredConfig>(runtimeConfigPath(), {});\n}\n\n/** A stable anonymous id for this machine's install -- never tied to an\n * account, just enough to keep one dwell/frequency bookkeeping identity. */\nexport function ensureInstallId(): string {\n\tconst existing = _read();\n\tif (existing.installId) return existing.installId;\n\tconst installId = randomUUID();\n\twriteJsonAtomic(runtimeConfigPath(), { ...existing, installId });\n\treturn installId;\n}\n\nexport function toSessionId(claudeSessionId: string | undefined): string {\n\treturn claudeSessionId ?? randomUUID();\n}\n\nexport function resolveRuntimeConfig(input: {\n\tapiKey: string;\n\tapiUrl?: string;\n\twebUrl?: string;\n\tenabled?: boolean;\n}): TRuntimeConfig {\n\treturn {\n\t\tapiKey: input.apiKey,\n\t\tapiUrl: input.apiUrl ?? DEFAULT_API_URL,\n\t\twebUrl: input.webUrl ?? DEFAULT_WEB_URL,\n\t\tenabled: input.enabled ?? true,\n\t\tinstallId: ensureInstallId(),\n\t\twebviewPatchedEditors: _read().webviewPatchedEditors ?? [],\n\t};\n}\n\nexport function writeRuntimeConfig(config: TRuntimeConfig): void {\n\twriteJsonAtomic(runtimeConfigPath(), config);\n}\n\n/** Merge-only update of just the patch-state list -- called by\n * `extension.ts` after `webviewPatch.ts` runs, separately from the rest of\n * `resolveRuntimeConfig`'s inputs so it never has to round-trip through\n * VS Code's settings to persist this. */\nexport function writeWebviewPatchedEditors(editorFolders: string[]): void {\n\tconst existing = _read();\n\twriteJsonAtomic(runtimeConfigPath(), {\n\t\t...existing,\n\t\twebviewPatchedEditors: editorFolders,\n\t});\n}\n\n/**\n * Clears the cached key on an explicit \"Kili: Sign Out\" -- see this file's\n * top doc comment for why this is scoped to the explicit sign-out path only,\n * never called from the implicit re-sign-in short-circuit. Everything else\n * in the file (`installId`, `webviewPatchedEditors`) is preserved: signing\n * out doesn't mean forgetting this device, just forgetting who's signed in\n * on it.\n */\nexport function clearCachedApiKey(): void {\n\tconst existing = _read();\n\twriteJsonAtomic(runtimeConfigPath(), { ...existing, apiKey: undefined });\n}\n\nexport function readRuntimeConfig(): TRuntimeConfig | null {\n\tconst stored = _read();\n\tif (!stored.apiKey || !stored.apiUrl || !stored.installId) return null;\n\treturn {\n\t\tapiKey: stored.apiKey,\n\t\tapiUrl: stored.apiUrl,\n\t\twebUrl: stored.webUrl ?? DEFAULT_WEB_URL,\n\t\tenabled: stored.enabled ?? true,\n\t\tinstallId: stored.installId,\n\t\twebviewPatchedEditors: stored.webviewPatchedEditors ?? [],\n\t};\n}\n","import {\n\texistsSync,\n\treadFileSync,\n\treaddirSync,\n\tstatSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\n/**\n * Patches Claude Code's own installed webview bundle so the spinner-verb\n * text can render a real clickable link -- something no supported setting\n * can do. Confirmed by reading the shipped source: `spinnerVerbsConfig`'s\n * verb text is rendered straight into a plain `<span>`'s `children`, with\n * no markdown/link parsing anywhere in that path (see `copy.ts`'s\n * `spinnerVerb()` doc comment). This is the deliberate, user-approved\n * exception to this package's \"official settings only, no patching\"\n * design -- explicit, disclosed in the consent prompt, and reversible.\n *\n * This WILL break whenever Claude Code ships a new webview build: every\n * `_ANCHOR` below is the EXACT, complete minified render function, copied\n * byte for byte from a real shipped file, not reconstructed from memory.\n * `readdirSync`ing for `anthropic.claude-code-*` finds whatever version is\n * actually installed; a version whose bundle doesn't match any known\n * anchor is left completely untouched, with a clear log line -- never\n * partially patched, never guessed at.\n */\n\nconst _MARKER = \"__kiliSpinnerLinkPatch\";\nconst _BACKUP_SUFFIX = \".kili-orig\";\n\ntype TAnchor = { version: string; find: string; replace: string };\n\n// One entry per verified Claude Code webview build. Each pair is the\n// M30/Mot-equivalent spinner-render component, unmodified except for the\n// inserted link-lookup logic -- everything else byte-identical to the\n// original, so a failed match never leaves a half-applied patch.\n//\n// Every `replace` also inserts one clause the original does not have:\n// `if(!Q.includes(H))H=Q[0]` (names vary per build). This fixes a real,\n// user-visible bug, and it is worth understanding before touching it.\n//\n// The component draws `H`, which comes from `useState`, and only ever\n// refreshes on Claude's own 2s/3s/5s re-pick timer. But the verb list `Q`\n// and the width `Z = max(verb.length)` are `useMemo`s keyed on the config,\n// so they update the instant a new ad is written. That leaves a window --\n// up to 5 seconds -- where the component renders the PREVIOUS turn's verb\n// at the NEW verb's width, and three separate symptoms all fall out of it:\n// 1. the previous ad stays on screen after a new turn starts;\n// 2. `rc0(H+\"...\", Z+3)` truncates that stale, longer text down to the\n// new, shorter width -- confirmed live, `[BOB: The Bank of Bitcoin]`\n// (26 chars) rendered as `[BOB: The Bank o`;\n// 3. the link and logo vanish, because the memo already cleared and\n// refilled the label->link map for the new list, so the stale `H` is\n// not a key in it and the component falls back to a plain `<span>`.\n// Clamping `H` into the current list makes all three impossible: the drawn\n// verb is always one the width was computed from, and always one the map\n// has an entry for. It is deliberately placed BEFORE the `\"Compacting\"`\n// override, which is intentionally not a member of the list.\nconst _ANCHORS: TAnchor[] = [\n\t{\n\t\tversion: \"2.1.258\",\n\t\tfind: 'function od0($){if(!$)return KH1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:KH1;return[...KH1,...$.verbs]}function s$0({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=C2(()=>od0(X),[X]),Z=C2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=J1(0),[z,U]=J1(()=>mi(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%a$0.length)},120);return()=>clearInterval(W)},[]),Vy(()=>{U(mi(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(Y===\"compacting\")H=\"Compacting\";let B=td0(H+\"...\",Z+3);return E(\"div\",{className:gi.container,\"data-permission-mode\":J,children:[D(\"span\",{\"aria-hidden\":\"true\",className:gi.icon,style:{fontSize:`${$}px`},children:a$0[G]}),D(\"span\",{\"aria-hidden\":\"true\",className:gi.text,children:B}),D(\"span\",{className:YN.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}',\n\t\treplace: `var ${_MARKER}=new Map();var __kiliLastLog=\"\";var __kiliLastGeom=\"\";function _kiliLog(o){try{var s=JSON.stringify(o);if(s===__kiliLastLog)return;__kiliLastLog=s;console.log(\"[kili]\",o)}catch(e){}}function _kiliParseLink(raw){let i=raw.indexOf(\"\\\\u0001\");if(i<0)return null;let rest=raw.slice(i+1);let j2=rest.indexOf(\"\\\\u0001\");return j2<0?{label:raw.slice(0,i),url:rest,logo:null}:{label:raw.slice(0,i),url:rest.slice(0,j2),logo:rest.slice(j2+1)}}function od0($){if(!$)return KH1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:KH1;return[...KH1,...$.verbs]}function s$0({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=C2(()=>{${_MARKER}.clear();return od0(X).map((raw)=>{let p=_kiliParseLink(raw);if(p){${_MARKER}.set(p.label,{url:p.url,logo:p.logo});return p.label}return raw})},[X]),Z=C2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=J1(0),[z,U]=J1(()=>mi(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%a$0.length)},120);return()=>clearInterval(W)},[]),Vy(()=>{U(mi(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(!Q.includes(H))H=Q[0];if(Y===\"compacting\")H=\"Compacting\";let B=H+\"...\",K=${_MARKER}.get(H);_kiliLog({labels:Q,width:Z,drawn:H,wasStale:!Q.includes(z),linked:!!K,hasLogo:!!(K&&K.logo)});return E(\"div\",{className:gi.container,style:{overflow:\"visible\",maxWidth:\"none\",width:\"auto\",flexWrap:\"nowrap\"},\"data-permission-mode\":J,children:[D(\"span\",{\"aria-hidden\":\"true\",className:gi.icon,style:{fontSize:\\`\\${$}px\\`},children:a$0[G]}),K?D(\"a\",{ref:(el)=>{if(!el)return;try{var sel=[],q=el.parentElement;for(var i=0;i<8&&q;i++){var qr=q.getBoundingClientRect();if(qr.height>80)break;var cn=(typeof q.className===\"string\"?q.className:\"\").trim();if(cn)sel.push(\".\"+cn.split(/\\\\s+/).join(\".\"));q=q.parentElement}if(sel.length){var id=\"__kiliUnclip\",st=document.getElementById(id);if(!st){st=document.createElement(\"style\");st.id=id;document.head.appendChild(st)}var css=sel.join(\",\")+\"{overflow:visible!important;max-width:none!important;min-width:0!important;flex-shrink:0!important;text-overflow:clip!important;white-space:nowrap!important;animation:none!important;transition:none!important}\";if(st.textContent!==css)st.textContent=css}setTimeout(function(){try{var o=[],n=el;for(var k=0;k<8&&n;k++){var c=getComputedStyle(n),r=n.getBoundingClientRect();o.push(k+\":\"+n.tagName+\" w=\"+Math.round(r.width)+\" h=\"+Math.round(r.height)+\" sw=\"+n.scrollWidth+\" tlen=\"+((n.textContent||\"\").length)+\" anim=\"+c.animationName+\" ovf=\"+c.overflow);n=n.parentElement}var g=o.join(\" | \");if(g!==__kiliLastGeom){__kiliLastGeom=g;console.log(\"[kili-geom]\",g)}}catch(e){}},50)}catch(e){}},\"aria-hidden\":\"true\",className:gi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},href:K.url,target:\"_blank\",rel:\"noopener noreferrer\",children:[K.logo?D(\"img\",{src:K.logo,alt:\"\",style:{width:\"14px\",height:\"14px\",borderRadius:\"3px\",objectFit:\"cover\",verticalAlign:\"middle\",marginRight:\"4px\"}}):null,B]}):D(\"span\",{\"aria-hidden\":\"true\",className:gi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},children:B}),D(\"span\",{className:YN.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}`,\n\t},\n\t{\n\t\tversion: \"2.1.251\",\n\t\tfind: 'function ac0($){if(!$)return TV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:TV1;return[...TV1,...$.verbs]}function L30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=t2(()=>ac0(X),[X]),Z=t2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Ki(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%R30.length)},120);return()=>clearInterval(W)},[]),sk(()=>{U(Ki(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(Y===\"compacting\")H=\"Compacting\";let B=rc0(H+\"...\",Z+3);return E(\"div\",{className:Fi.container,\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Fi.icon,style:{fontSize:`${$}px`},children:R30[G]}),j(\"span\",{\"aria-hidden\":\"true\",className:Fi.text,children:B}),j(\"span\",{className:aO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}',\n\t\treplace: `var ${_MARKER}=new Map();var __kiliLastLog=\"\";var __kiliLastGeom=\"\";function _kiliLog(o){try{var s=JSON.stringify(o);if(s===__kiliLastLog)return;__kiliLastLog=s;console.log(\"[kili]\",o)}catch(e){}}function _kiliParseLink(raw){let i=raw.indexOf(\"\\\\u0001\");if(i<0)return null;let rest=raw.slice(i+1);let j2=rest.indexOf(\"\\\\u0001\");return j2<0?{label:raw.slice(0,i),url:rest,logo:null}:{label:raw.slice(0,i),url:rest.slice(0,j2),logo:rest.slice(j2+1)}}function ac0($){if(!$)return TV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:TV1;return[...TV1,...$.verbs]}function L30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=t2(()=>{${_MARKER}.clear();return ac0(X).map((raw)=>{let p=_kiliParseLink(raw);if(p){${_MARKER}.set(p.label,{url:p.url,logo:p.logo});return p.label}return raw})},[X]),Z=t2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Ki(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%R30.length)},120);return()=>clearInterval(W)},[]),sk(()=>{U(Ki(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(!Q.includes(H))H=Q[0];if(Y===\"compacting\")H=\"Compacting\";let B=H+\"...\",K=${_MARKER}.get(H);_kiliLog({labels:Q,width:Z,drawn:H,wasStale:!Q.includes(z),linked:!!K,hasLogo:!!(K&&K.logo)});return E(\"div\",{className:Fi.container,style:{overflow:\"visible\",maxWidth:\"none\",width:\"auto\",flexWrap:\"nowrap\"},\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Fi.icon,style:{fontSize:\\`\\${$}px\\`},children:R30[G]}),K?j(\"a\",{ref:(el)=>{if(!el)return;try{var sel=[],q=el.parentElement;for(var i=0;i<8&&q;i++){var qr=q.getBoundingClientRect();if(qr.height>80)break;var cn=(typeof q.className===\"string\"?q.className:\"\").trim();if(cn)sel.push(\".\"+cn.split(/\\\\s+/).join(\".\"));q=q.parentElement}if(sel.length){var id=\"__kiliUnclip\",st=document.getElementById(id);if(!st){st=document.createElement(\"style\");st.id=id;document.head.appendChild(st)}var css=sel.join(\",\")+\"{overflow:visible!important;max-width:none!important;min-width:0!important;flex-shrink:0!important;text-overflow:clip!important;white-space:nowrap!important;animation:none!important;transition:none!important}\";if(st.textContent!==css)st.textContent=css}setTimeout(function(){try{var o=[],n=el;for(var k=0;k<8&&n;k++){var c=getComputedStyle(n),r=n.getBoundingClientRect();o.push(k+\":\"+n.tagName+\" w=\"+Math.round(r.width)+\" h=\"+Math.round(r.height)+\" sw=\"+n.scrollWidth+\" tlen=\"+((n.textContent||\"\").length)+\" anim=\"+c.animationName+\" ovf=\"+c.overflow);n=n.parentElement}var g=o.join(\" | \");if(g!==__kiliLastGeom){__kiliLastGeom=g;console.log(\"[kili-geom]\",g)}}catch(e){}},50)}catch(e){}},\"aria-hidden\":\"true\",className:Fi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},href:K.url,target:\"_blank\",rel:\"noopener noreferrer\",children:[K.logo?j(\"img\",{src:K.logo,alt:\"\",style:{width:\"14px\",height:\"14px\",borderRadius:\"3px\",objectFit:\"cover\",verticalAlign:\"middle\",marginRight:\"4px\"}}):null,B]}):j(\"span\",{\"aria-hidden\":\"true\",className:Fi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},children:B}),j(\"span\",{className:aO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}`,\n\t},\n\t{\n\t\tversion: \"2.1.250\",\n\t\tfind: 'function cc0($){if(!$)return NV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:NV1;return[...NV1,...$.verbs]}function R30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=o2(()=>cc0(X),[X]),Z=o2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Ki(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%w30.length)},120);return()=>clearInterval(W)},[]),rk(()=>{U(Ki(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(Y===\"compacting\")H=\"Compacting\";let B=lc0(H+\"...\",Z+3);return E(\"div\",{className:Fi.container,\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Fi.icon,style:{fontSize:`${$}px`},children:w30[G]}),j(\"span\",{\"aria-hidden\":\"true\",className:Fi.text,children:B}),j(\"span\",{className:dO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}',\n\t\treplace: `var ${_MARKER}=new Map();var __kiliLastLog=\"\";var __kiliLastGeom=\"\";function _kiliLog(o){try{var s=JSON.stringify(o);if(s===__kiliLastLog)return;__kiliLastLog=s;console.log(\"[kili]\",o)}catch(e){}}function _kiliParseLink(raw){let i=raw.indexOf(\"\\\\u0001\");if(i<0)return null;let rest=raw.slice(i+1);let j2=rest.indexOf(\"\\\\u0001\");return j2<0?{label:raw.slice(0,i),url:rest,logo:null}:{label:raw.slice(0,i),url:rest.slice(0,j2),logo:rest.slice(j2+1)}}function cc0($){if(!$)return NV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:NV1;return[...NV1,...$.verbs]}function R30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=o2(()=>{${_MARKER}.clear();return cc0(X).map((raw)=>{let p=_kiliParseLink(raw);if(p){${_MARKER}.set(p.label,{url:p.url,logo:p.logo});return p.label}return raw})},[X]),Z=o2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Ki(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%w30.length)},120);return()=>clearInterval(W)},[]),rk(()=>{U(Ki(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(!Q.includes(H))H=Q[0];if(Y===\"compacting\")H=\"Compacting\";let B=H+\"...\",K=${_MARKER}.get(H);_kiliLog({labels:Q,width:Z,drawn:H,wasStale:!Q.includes(z),linked:!!K,hasLogo:!!(K&&K.logo)});return E(\"div\",{className:Fi.container,style:{overflow:\"visible\",maxWidth:\"none\",width:\"auto\",flexWrap:\"nowrap\"},\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Fi.icon,style:{fontSize:\\`\\${$}px\\`},children:w30[G]}),K?j(\"a\",{ref:(el)=>{if(!el)return;try{var sel=[],q=el.parentElement;for(var i=0;i<8&&q;i++){var qr=q.getBoundingClientRect();if(qr.height>80)break;var cn=(typeof q.className===\"string\"?q.className:\"\").trim();if(cn)sel.push(\".\"+cn.split(/\\\\s+/).join(\".\"));q=q.parentElement}if(sel.length){var id=\"__kiliUnclip\",st=document.getElementById(id);if(!st){st=document.createElement(\"style\");st.id=id;document.head.appendChild(st)}var css=sel.join(\",\")+\"{overflow:visible!important;max-width:none!important;min-width:0!important;flex-shrink:0!important;text-overflow:clip!important;white-space:nowrap!important;animation:none!important;transition:none!important}\";if(st.textContent!==css)st.textContent=css}setTimeout(function(){try{var o=[],n=el;for(var k=0;k<8&&n;k++){var c=getComputedStyle(n),r=n.getBoundingClientRect();o.push(k+\":\"+n.tagName+\" w=\"+Math.round(r.width)+\" h=\"+Math.round(r.height)+\" sw=\"+n.scrollWidth+\" tlen=\"+((n.textContent||\"\").length)+\" anim=\"+c.animationName+\" ovf=\"+c.overflow);n=n.parentElement}var g=o.join(\" | \");if(g!==__kiliLastGeom){__kiliLastGeom=g;console.log(\"[kili-geom]\",g)}}catch(e){}},50)}catch(e){}},\"aria-hidden\":\"true\",className:Fi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},href:K.url,target:\"_blank\",rel:\"noopener noreferrer\",children:[K.logo?j(\"img\",{src:K.logo,alt:\"\",style:{width:\"14px\",height:\"14px\",borderRadius:\"3px\",objectFit:\"cover\",verticalAlign:\"middle\",marginRight:\"4px\"}}):null,B]}):j(\"span\",{\"aria-hidden\":\"true\",className:Fi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},children:B}),j(\"span\",{className:dO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}`,\n\t},\n\t{\n\t\tversion: \"2.1.247\",\n\t\tfind: 'function Ec0($){if(!$)return RV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:RV1;return[...RV1,...$.verbs]}function w30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=o2(()=>Ec0(X),[X]),Z=o2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Fi(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%M30.length)},120);return()=>clearInterval(W)},[]),rk(()=>{U(Fi(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(Y===\"compacting\")H=\"Compacting\";let B=Ic0(H+\"...\",Z+3);return E(\"div\",{className:Wi.container,\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Wi.icon,style:{fontSize:`${$}px`},children:M30[G]}),j(\"span\",{\"aria-hidden\":\"true\",className:Wi.text,children:B}),j(\"span\",{className:dO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}',\n\t\treplace: `var ${_MARKER}=new Map();var __kiliLastLog=\"\";var __kiliLastGeom=\"\";function _kiliLog(o){try{var s=JSON.stringify(o);if(s===__kiliLastLog)return;__kiliLastLog=s;console.log(\"[kili]\",o)}catch(e){}}function _kiliParseLink(raw){let i=raw.indexOf(\"\\\\u0001\");if(i<0)return null;let rest=raw.slice(i+1);let j2=rest.indexOf(\"\\\\u0001\");return j2<0?{label:raw.slice(0,i),url:rest,logo:null}:{label:raw.slice(0,i),url:rest.slice(0,j2),logo:rest.slice(j2+1)}}function Ec0($){if(!$)return RV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:RV1;return[...RV1,...$.verbs]}function w30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=o2(()=>{${_MARKER}.clear();return Ec0(X).map((raw)=>{let p=_kiliParseLink(raw);if(p){${_MARKER}.set(p.label,{url:p.url,logo:p.logo});return p.label}return raw})},[X]),Z=o2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Fi(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%M30.length)},120);return()=>clearInterval(W)},[]),rk(()=>{U(Fi(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(!Q.includes(H))H=Q[0];if(Y===\"compacting\")H=\"Compacting\";let B=H+\"...\",K=${_MARKER}.get(H);_kiliLog({labels:Q,width:Z,drawn:H,wasStale:!Q.includes(z),linked:!!K,hasLogo:!!(K&&K.logo)});return E(\"div\",{className:Wi.container,style:{overflow:\"visible\",maxWidth:\"none\",width:\"auto\",flexWrap:\"nowrap\"},\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Wi.icon,style:{fontSize:\\`\\${$}px\\`},children:M30[G]}),K?j(\"a\",{ref:(el)=>{if(!el)return;try{var sel=[],q=el.parentElement;for(var i=0;i<8&&q;i++){var qr=q.getBoundingClientRect();if(qr.height>80)break;var cn=(typeof q.className===\"string\"?q.className:\"\").trim();if(cn)sel.push(\".\"+cn.split(/\\\\s+/).join(\".\"));q=q.parentElement}if(sel.length){var id=\"__kiliUnclip\",st=document.getElementById(id);if(!st){st=document.createElement(\"style\");st.id=id;document.head.appendChild(st)}var css=sel.join(\",\")+\"{overflow:visible!important;max-width:none!important;min-width:0!important;flex-shrink:0!important;text-overflow:clip!important;white-space:nowrap!important;animation:none!important;transition:none!important}\";if(st.textContent!==css)st.textContent=css}setTimeout(function(){try{var o=[],n=el;for(var k=0;k<8&&n;k++){var c=getComputedStyle(n),r=n.getBoundingClientRect();o.push(k+\":\"+n.tagName+\" w=\"+Math.round(r.width)+\" h=\"+Math.round(r.height)+\" sw=\"+n.scrollWidth+\" tlen=\"+((n.textContent||\"\").length)+\" anim=\"+c.animationName+\" ovf=\"+c.overflow);n=n.parentElement}var g=o.join(\" | \");if(g!==__kiliLastGeom){__kiliLastGeom=g;console.log(\"[kili-geom]\",g)}}catch(e){}},50)}catch(e){}},\"aria-hidden\":\"true\",className:Wi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},href:K.url,target:\"_blank\",rel:\"noopener noreferrer\",children:[K.logo?j(\"img\",{src:K.logo,alt:\"\",style:{width:\"14px\",height:\"14px\",borderRadius:\"3px\",objectFit:\"cover\",verticalAlign:\"middle\",marginRight:\"4px\"}}):null,B]}):j(\"span\",{\"aria-hidden\":\"true\",className:Wi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},children:B}),j(\"span\",{className:dO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}`,\n\t},\n\t{\n\t\tversion: \"2.1.246\",\n\t\tfind: 'function Tc0($){if(!$)return RV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:RV1;return[...RV1,...$.verbs]}function _30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=i2(()=>Tc0(X),[X]),Z=i2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Fi(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%P30.length)},120);return()=>clearInterval(W)},[]),rk(()=>{U(Fi(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(Y===\"compacting\")H=\"Compacting\";let B=Ec0(H+\"...\",Z+3);return E(\"div\",{className:Wi.container,\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Wi.icon,style:{fontSize:`${$}px`},children:P30[G]}),j(\"span\",{\"aria-hidden\":\"true\",className:Wi.text,children:B}),j(\"span\",{className:dO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}',\n\t\treplace: `var ${_MARKER}=new Map();var __kiliLastLog=\"\";var __kiliLastGeom=\"\";function _kiliLog(o){try{var s=JSON.stringify(o);if(s===__kiliLastLog)return;__kiliLastLog=s;console.log(\"[kili]\",o)}catch(e){}}function _kiliParseLink(raw){let i=raw.indexOf(\"\\\\u0001\");if(i<0)return null;let rest=raw.slice(i+1);let j2=rest.indexOf(\"\\\\u0001\");return j2<0?{label:raw.slice(0,i),url:rest,logo:null}:{label:raw.slice(0,i),url:rest.slice(0,j2),logo:rest.slice(j2+1)}}function Tc0($){if(!$)return RV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:RV1;return[...RV1,...$.verbs]}function _30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=i2(()=>{${_MARKER}.clear();return Tc0(X).map((raw)=>{let p=_kiliParseLink(raw);if(p){${_MARKER}.set(p.label,{url:p.url,logo:p.logo});return p.label}return raw})},[X]),Z=i2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Fi(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%P30.length)},120);return()=>clearInterval(W)},[]),rk(()=>{U(Fi(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(!Q.includes(H))H=Q[0];if(Y===\"compacting\")H=\"Compacting\";let B=H+\"...\",K=${_MARKER}.get(H);_kiliLog({labels:Q,width:Z,drawn:H,wasStale:!Q.includes(z),linked:!!K,hasLogo:!!(K&&K.logo)});return E(\"div\",{className:Wi.container,style:{overflow:\"visible\",maxWidth:\"none\",width:\"auto\",flexWrap:\"nowrap\"},\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Wi.icon,style:{fontSize:\\`\\${$}px\\`},children:P30[G]}),K?j(\"a\",{ref:(el)=>{if(!el)return;try{var sel=[],q=el.parentElement;for(var i=0;i<8&&q;i++){var qr=q.getBoundingClientRect();if(qr.height>80)break;var cn=(typeof q.className===\"string\"?q.className:\"\").trim();if(cn)sel.push(\".\"+cn.split(/\\\\s+/).join(\".\"));q=q.parentElement}if(sel.length){var id=\"__kiliUnclip\",st=document.getElementById(id);if(!st){st=document.createElement(\"style\");st.id=id;document.head.appendChild(st)}var css=sel.join(\",\")+\"{overflow:visible!important;max-width:none!important;min-width:0!important;flex-shrink:0!important;text-overflow:clip!important;white-space:nowrap!important;animation:none!important;transition:none!important}\";if(st.textContent!==css)st.textContent=css}setTimeout(function(){try{var o=[],n=el;for(var k=0;k<8&&n;k++){var c=getComputedStyle(n),r=n.getBoundingClientRect();o.push(k+\":\"+n.tagName+\" w=\"+Math.round(r.width)+\" h=\"+Math.round(r.height)+\" sw=\"+n.scrollWidth+\" tlen=\"+((n.textContent||\"\").length)+\" anim=\"+c.animationName+\" ovf=\"+c.overflow);n=n.parentElement}var g=o.join(\" | \");if(g!==__kiliLastGeom){__kiliLastGeom=g;console.log(\"[kili-geom]\",g)}}catch(e){}},50)}catch(e){}},\"aria-hidden\":\"true\",className:Wi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},href:K.url,target:\"_blank\",rel:\"noopener noreferrer\",children:[K.logo?j(\"img\",{src:K.logo,alt:\"\",style:{width:\"14px\",height:\"14px\",borderRadius:\"3px\",objectFit:\"cover\",verticalAlign:\"middle\",marginRight:\"4px\"}}):null,B]}):j(\"span\",{\"aria-hidden\":\"true\",className:Wi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},children:B}),j(\"span\",{className:dO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}`,\n\t},\n\t{\n\t\tversion: \"2.1.245\",\n\t\tfind: 'function Lc0($){if(!$)return wV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:wV1;return[...wV1,...$.verbs]}function M30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=i2(()=>Lc0(X),[X]),Z=i2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Bi(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%j30.length)},120);return()=>clearInterval(W)},[]),dk(()=>{U(Bi(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(Y===\"compacting\")H=\"Compacting\";let B=Tc0(H+\"...\",Z+3);return E(\"div\",{className:Hi.container,\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Hi.icon,style:{fontSize:`${$}px`},children:j30[G]}),j(\"span\",{\"aria-hidden\":\"true\",className:Hi.text,children:B}),j(\"span\",{className:lO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}',\n\t\treplace: `var ${_MARKER}=new Map();var __kiliLastLog=\"\";var __kiliLastGeom=\"\";function _kiliLog(o){try{var s=JSON.stringify(o);if(s===__kiliLastLog)return;__kiliLastLog=s;console.log(\"[kili]\",o)}catch(e){}}function _kiliParseLink(raw){let i=raw.indexOf(\"\\\\u0001\");if(i<0)return null;let rest=raw.slice(i+1);let j2=rest.indexOf(\"\\\\u0001\");return j2<0?{label:raw.slice(0,i),url:rest,logo:null}:{label:raw.slice(0,i),url:rest.slice(0,j2),logo:rest.slice(j2+1)}}function Lc0($){if(!$)return wV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:wV1;return[...wV1,...$.verbs]}function M30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=i2(()=>{${_MARKER}.clear();return Lc0(X).map((raw)=>{let p=_kiliParseLink(raw);if(p){${_MARKER}.set(p.label,{url:p.url,logo:p.logo});return p.label}return raw})},[X]),Z=i2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Bi(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%j30.length)},120);return()=>clearInterval(W)},[]),dk(()=>{U(Bi(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(!Q.includes(H))H=Q[0];if(Y===\"compacting\")H=\"Compacting\";let B=H+\"...\",K=${_MARKER}.get(H);_kiliLog({labels:Q,width:Z,drawn:H,wasStale:!Q.includes(z),linked:!!K,hasLogo:!!(K&&K.logo)});return E(\"div\",{className:Hi.container,style:{overflow:\"visible\",maxWidth:\"none\",width:\"auto\",flexWrap:\"nowrap\"},\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Hi.icon,style:{fontSize:\\`\\${$}px\\`},children:j30[G]}),K?j(\"a\",{ref:(el)=>{if(!el)return;try{var sel=[],q=el.parentElement;for(var i=0;i<8&&q;i++){var qr=q.getBoundingClientRect();if(qr.height>80)break;var cn=(typeof q.className===\"string\"?q.className:\"\").trim();if(cn)sel.push(\".\"+cn.split(/\\\\s+/).join(\".\"));q=q.parentElement}if(sel.length){var id=\"__kiliUnclip\",st=document.getElementById(id);if(!st){st=document.createElement(\"style\");st.id=id;document.head.appendChild(st)}var css=sel.join(\",\")+\"{overflow:visible!important;max-width:none!important;min-width:0!important;flex-shrink:0!important;text-overflow:clip!important;white-space:nowrap!important;animation:none!important;transition:none!important}\";if(st.textContent!==css)st.textContent=css}setTimeout(function(){try{var o=[],n=el;for(var k=0;k<8&&n;k++){var c=getComputedStyle(n),r=n.getBoundingClientRect();o.push(k+\":\"+n.tagName+\" w=\"+Math.round(r.width)+\" h=\"+Math.round(r.height)+\" sw=\"+n.scrollWidth+\" tlen=\"+((n.textContent||\"\").length)+\" anim=\"+c.animationName+\" ovf=\"+c.overflow);n=n.parentElement}var g=o.join(\" | \");if(g!==__kiliLastGeom){__kiliLastGeom=g;console.log(\"[kili-geom]\",g)}}catch(e){}},50)}catch(e){}},\"aria-hidden\":\"true\",className:Hi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},href:K.url,target:\"_blank\",rel:\"noopener noreferrer\",children:[K.logo?j(\"img\",{src:K.logo,alt:\"\",style:{width:\"14px\",height:\"14px\",borderRadius:\"3px\",objectFit:\"cover\",verticalAlign:\"middle\",marginRight:\"4px\"}}):null,B]}):j(\"span\",{\"aria-hidden\":\"true\",className:Hi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},children:B}),j(\"span\",{className:lO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}`,\n\t},\n\t{\n\t\tversion: \"2.1.232\",\n\t\tfind: 'function cBt(e){if(!e)return r0e;if(e.mode===\"replace\")return e.verbs.length>0?e.verbs:r0e;return[...r0e,...e.verbs]}function Mot({size:e=16,permissionMode:t,status:i,spinnerVerbsConfig:n}){let o=Jn(()=>cBt(n),[n]),r=Jn(()=>Math.max(...o.map((p)=>p.length)),[o]),[s,a]=ne(0),[l,c]=ne(()=>LG(o));se(()=>{let p=setInterval(()=>{a((f)=>(f+1)%Rot.length)},120);return()=>clearInterval(p)},[]),o0e(()=>{c(LG(o))},(p)=>{let f=[2000,3000,5000];return p<f.length?f[p]:5000});let u=l;if(i===\"compacting\")u=\"Compacting\";let h=dBt(u+\"...\",r+3);return I(\"div\",{className:kG.container,\"data-permission-mode\":t,children:[b(\"span\",{className:kG.icon,style:{fontSize:`${e}px`},children:Rot[s]}),b(\"span\",{className:kG.text,children:h})]})}',\n\t\treplace: `var ${_MARKER}=new Map();var __kiliLastLog=\"\";var __kiliLastGeom=\"\";function _kiliLog(o){try{var s=JSON.stringify(o);if(s===__kiliLastLog)return;__kiliLastLog=s;console.log(\"[kili]\",o)}catch(e){}}function _kiliParseLink(raw){let i=raw.indexOf(\"\\\\u0001\");if(i<0)return null;let rest=raw.slice(i+1);let j2=rest.indexOf(\"\\\\u0001\");return j2<0?{label:raw.slice(0,i),url:rest,logo:null}:{label:raw.slice(0,i),url:rest.slice(0,j2),logo:rest.slice(j2+1)}}function cBt(e){if(!e)return r0e;if(e.mode===\"replace\")return e.verbs.length>0?e.verbs:r0e;return[...r0e,...e.verbs]}function Mot({size:e=16,permissionMode:t,status:i,spinnerVerbsConfig:n}){let o=Jn(()=>{${_MARKER}.clear();return cBt(n).map((raw)=>{let p=_kiliParseLink(raw);if(p){${_MARKER}.set(p.label,{url:p.url,logo:p.logo});return p.label}return raw})},[n]),r=Jn(()=>Math.max(...o.map((p)=>p.length)),[o]),[s,a]=ne(0),[l,c]=ne(()=>LG(o));se(()=>{let p=setInterval(()=>{a((f)=>(f+1)%Rot.length)},120);return()=>clearInterval(p)},[]),o0e(()=>{c(LG(o))},(p)=>{let f=[2000,3000,5000];return p<f.length?f[p]:5000});let u=l;if(!o.includes(u))u=o[0];if(i===\"compacting\")u=\"Compacting\";let h=u+\"...\",K=${_MARKER}.get(u);_kiliLog({labels:o,width:r,drawn:u,wasStale:!o.includes(l),linked:!!K,hasLogo:!!(K&&K.logo)});return I(\"div\",{className:kG.container,style:{overflow:\"visible\",maxWidth:\"none\",width:\"auto\",flexWrap:\"nowrap\"},\"data-permission-mode\":t,children:[b(\"span\",{className:kG.icon,style:{fontSize:\\`\\${e}px\\`},children:Rot[s]}),K?b(\"a\",{ref:(el)=>{if(!el)return;try{var sel=[],q=el.parentElement;for(var i=0;i<8&&q;i++){var qr=q.getBoundingClientRect();if(qr.height>80)break;var cn=(typeof q.className===\"string\"?q.className:\"\").trim();if(cn)sel.push(\".\"+cn.split(/\\\\s+/).join(\".\"));q=q.parentElement}if(sel.length){var id=\"__kiliUnclip\",st=document.getElementById(id);if(!st){st=document.createElement(\"style\");st.id=id;document.head.appendChild(st)}var css=sel.join(\",\")+\"{overflow:visible!important;max-width:none!important;min-width:0!important;flex-shrink:0!important;text-overflow:clip!important;white-space:nowrap!important;animation:none!important;transition:none!important}\";if(st.textContent!==css)st.textContent=css}setTimeout(function(){try{var o=[],n=el;for(var k=0;k<8&&n;k++){var c=getComputedStyle(n),r=n.getBoundingClientRect();o.push(k+\":\"+n.tagName+\" w=\"+Math.round(r.width)+\" h=\"+Math.round(r.height)+\" sw=\"+n.scrollWidth+\" tlen=\"+((n.textContent||\"\").length)+\" anim=\"+c.animationName+\" ovf=\"+c.overflow);n=n.parentElement}var g=o.join(\" | \");if(g!==__kiliLastGeom){__kiliLastGeom=g;console.log(\"[kili-geom]\",g)}}catch(e){}},50)}catch(e){}},className:kG.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},href:K.url,target:\"_blank\",rel:\"noopener noreferrer\",children:[K.logo?b(\"img\",{src:K.logo,alt:\"\",style:{width:\"14px\",height:\"14px\",borderRadius:\"3px\",objectFit:\"cover\",verticalAlign:\"middle\",marginRight:\"4px\"}}):null,h]}):b(\"span\",{className:kG.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},children:h})]})}`,\n\t},\n];\n\nexport type TPatchResult = \"patched\" | \"already-patched\" | \"no-match\" | \"error\";\n\n// Built via fromCharCode, not a literal byte in source -- this file has\n// previously been bitten by literal control bytes landing silently in\n// source text instead of an escape sequence (see copy.ts). SOH (0x01) can\n// never appear in real ad copy, so it needs no further escaping.\nconst _LINK_SEP = String.fromCharCode(1);\n\n/** Encodes a clickable, optionally logo'd spinner verb for `_kiliParseLink`\n * (see `_ANCHORS` above) to split back into a label, a url, and an optional\n * logo image url. The logo segment is only appended when present, so a\n * two-segment encoding (no logo) still round-trips through the same parser\n * unchanged. */\nexport function encodeLinkedVerb(\n\tlabel: string,\n\turl: string,\n\tlogoUrl?: string,\n): string {\n\treturn logoUrl\n\t\t? `${label}${_LINK_SEP}${url}${_LINK_SEP}${logoUrl}`\n\t\t: `${label}${_LINK_SEP}${url}`;\n}\n\n/**\n * Re-patching an already-patched bundle: the fix cannot be applied on top of\n * itself (the `find` anchor is the ORIGINAL shipped code, which the patched\n * file no longer contains), so a bundle carrying an older patch has to be\n * restored from its `.kili-orig` backup first and then patched fresh.\n *\n * Without this, `patchFile` returned `\"already-patched\"` for any file bearing\n * the marker and stopped -- meaning every future fix to the injected code\n * (the stale-verb clamp, the width guard, the layout styles, this logging)\n * would ship in the extension, be reported as installed, and silently never\n * reach the running webview of anyone who was already patched. That is\n * exactly the class of \"the fix is published but nothing changed\" loop that\n * makes this component so expensive to debug, so the version is embedded in\n * the file itself rather than tracked in config: the bundle states which\n * patch it is carrying, and disagreement is self-correcting.\n */\nconst _PATCH_VERSION = \"9\";\nconst _VERSION_TAG = `${_MARKER}_v${_PATCH_VERSION}`;\n/** Exported for tests only -- lets `editorSettings.test.ts` fabricate an\n * already-patched webview file without duplicating a real minified anchor\n * string just to exercise `isCurrentlyPatched()`. */\nexport const TEST_ONLY_VERSION_TAG = _VERSION_TAG;\n\nexport function patchFile(filePath: string): TPatchResult {\n\ttry {\n\t\tif (!existsSync(filePath)) return \"error\";\n\t\tlet original = readFileSync(filePath, \"utf8\");\n\n\t\tif (original.includes(_VERSION_TAG)) return \"already-patched\";\n\n\t\t// Carries an OLDER patch: roll back to pristine so the anchor matches\n\t\t// again, then fall through and apply the current one.\n\t\tif (original.includes(_MARKER)) {\n\t\t\tconst backupPath = `${filePath}${_BACKUP_SUFFIX}`;\n\t\t\tif (!existsSync(backupPath)) return \"error\";\n\t\t\toriginal = readFileSync(backupPath, \"utf8\");\n\t\t\twriteFileSync(filePath, original, \"utf8\");\n\t\t}\n\n\t\tconst anchor = _ANCHORS.find((a) => original.includes(a.find));\n\t\tif (!anchor) return \"no-match\";\n\t\tconst patched = `/*${_VERSION_TAG}*/${original.replace(anchor.find, anchor.replace)}`;\n\t\tif (!existsSync(`${filePath}${_BACKUP_SUFFIX}`)) {\n\t\t\twriteFileSync(`${filePath}${_BACKUP_SUFFIX}`, original, \"utf8\");\n\t\t}\n\t\twriteFileSync(filePath, patched, \"utf8\");\n\t\treturn \"patched\";\n\t} catch {\n\t\treturn \"error\";\n\t}\n}\n\nexport function restoreFile(filePath: string): boolean {\n\tconst backupPath = `${filePath}${_BACKUP_SUFFIX}`;\n\ttry {\n\t\tif (!existsSync(backupPath)) return false;\n\t\twriteFileSync(filePath, readFileSync(backupPath, \"utf8\"), \"utf8\");\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/** One installed Claude Code webview file, tagged with the same editor-folder\n * name `editorSettings.ts`'s `_userSettingsFolder` uses (\"Cursor\" / \"Code\" /\n * \"VSCodium\") -- this is what lets patch success be tracked per editor\n * instead of as one global flag. Different editors update Claude Code on\n * their own schedule, so it's normal for one to be on a build we have an\n * anchor for while another is on a newer one we don't -- see `_ANCHORS`'s\n * doc comment. */\nexport type TWebviewFile = { editorFolder: string; filePath: string };\n\n/** Parses the leading `X.Y.Z` out of an `anthropic.claude-code-<version>`\n * (or `...-<version>-<platform>-<arch>`) extension folder name. `null` for\n * anything that doesn't match, so callers can fall back to mtime. */\nfunction _parseVersion(folderName: string): [number, number, number] | null {\n\tconst m = folderName.match(/^anthropic\\.claude-code-(\\d+)\\.(\\d+)\\.(\\d+)/);\n\tif (!m) return null;\n\treturn [Number(m[1]), Number(m[2]), Number(m[3])];\n}\n\n/** Every installed Claude Code webview bundle across every editor on this\n * machine (Cursor, VS Code, VSCodium) -- there's no `vscode` API to ask\n * \"which editor is this,\" so, same as `editorSettings.ts`, this patches\n * whichever ones actually exist on disk.\n *\n * Exactly ONE file per editor, the newest installed version -- VS Code\n * usually removes an extension's old version folder the moment it updates,\n * but not always immediately (confirmed live: a machine with BOTH\n * `anthropic.claude-code-2.1.252-...` and a newer `...-2.1.258-...`\n * sitting side by side at once, the update not yet cleaned up). Returning\n * every matching folder used to mean an editor with an old, still-patched\n * leftover folder AND a newer, genuinely-unpatched one both got reported as\n * \"this editor is patched\" -- `isCurrentlyPatched`/`applyToAllInstalled`\n * only need the version that's actually loaded and rendering right now,\n * which is always the newest one, never an update's stale leftover.\n */\nexport function findClaudeCodeWebviewFiles(): TWebviewFile[] {\n\t// `~/.vscode`, `~/.cursor`, `~/.vscode-oss` -- unlike settings.json's\n\t// per-OS \"Application Support\" path, each editor's extensions folder\n\t// lives directly under the home directory on every platform, so\n\t// `homedir()` alone is enough. This used to key off `USERPROFILE`, a\n\t// Windows-only env var that is always `undefined` on macOS/Linux --\n\t// meaning this returned no files, the patch silently never ran, and\n\t// every non-Windows install fell back to plain unclickable text no\n\t// matter how well-supported its webview build was. Confirmed live: this\n\t// was breaking every macOS install until now.\n\tconst home = homedir();\n\tconst extensionRoots: Array<{ editorFolder: string; root: string }> = [\n\t\t{ editorFolder: \"Cursor\", root: join(home, \".cursor\", \"extensions\") },\n\t\t{ editorFolder: \"Code\", root: join(home, \".vscode\", \"extensions\") },\n\t\t{\n\t\t\teditorFolder: \"VSCodium\",\n\t\t\troot: join(home, \".vscode-oss\", \"extensions\"),\n\t\t},\n\t];\n\n\tconst found: TWebviewFile[] = [];\n\tfor (const { editorFolder, root } of extensionRoots) {\n\t\tif (!existsSync(root)) continue;\n\t\tlet entries: string[] = [];\n\t\ttry {\n\t\t\tentries = readdirSync(root);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\t// Candidates for THIS editor only -- version-compared against each\n\t\t// other below, never across editors.\n\t\tconst candidates: Array<{\n\t\t\tfilePath: string;\n\t\t\tversion: [number, number, number] | null;\n\t\t\tmtimeMs: number;\n\t\t}> = [];\n\t\tfor (const entry of entries) {\n\t\t\tif (!entry.startsWith(\"anthropic.claude-code-\")) continue;\n\t\t\tconst filePath = join(root, entry, \"webview\", \"index.js\");\n\t\t\tif (!existsSync(filePath)) continue;\n\t\t\tlet mtimeMs = 0;\n\t\t\ttry {\n\t\t\t\tmtimeMs = statSync(filePath).mtimeMs;\n\t\t\t} catch {\n\t\t\t\t/* fall through with mtimeMs 0 -- version comparison still applies */\n\t\t\t}\n\t\t\tcandidates.push({ filePath, version: _parseVersion(entry), mtimeMs });\n\t\t}\n\t\tif (candidates.length === 0) continue;\n\t\t// Highest parsed version wins; unparseable folder names (or a tie)\n\t\t// fall back to the newest mtime.\n\t\tconst newest = candidates.reduce((best, c) => {\n\t\t\tif (c.version && best.version) {\n\t\t\t\tfor (let i = 0; i < 3; i++) {\n\t\t\t\t\tif (c.version[i] !== best.version[i]) {\n\t\t\t\t\t\treturn c.version[i] > best.version[i] ? c : best;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn c.mtimeMs > best.mtimeMs ? c : best;\n\t\t\t}\n\t\t\tif (c.version && !best.version) return c;\n\t\t\tif (!c.version && best.version) return best;\n\t\t\treturn c.mtimeMs > best.mtimeMs ? c : best;\n\t\t});\n\t\tfound.push({ editorFolder, filePath: newest.filePath });\n\t}\n\treturn found;\n}\n\n/**\n * Live, on-disk answer to \"is this editor's Claude Code webview actually\n * patched RIGHT NOW\" -- reads the current file(s) fresh, never trusts a\n * cached flag. `~/.kili/config.json`'s `webviewPatchedEditors` is a snapshot\n * from whenever `_applyWebviewPatch()` last ran (extension activation, or a\n * `kili.*` config change) -- it goes stale the moment Claude Code\n * auto-updates itself in between: a version bump replaces\n * `anthropic.claude-code-<old>/webview/index.js` with a brand new,\n * unpatched `anthropic.claude-code-<new>/webview/index.js`, and nothing\n * re-runs the patch until this extension's host next activates or its\n * config changes -- which, for a long-running editor window, can be a long\n * time, or never before the next restart. In that window, the stale cache\n * still says \"patched\", so `editorSettings.ts` kept sending the\n * link-encoded verb to a webview that had already reverted to plain,\n * unpatched code -- rendering as visible raw `[label]\u0001url` garbage\n * text instead of a link. Confirmed live: exactly this happened after a\n * Claude Code auto-update with no editor reload in between.\n *\n * Cheap enough to call on every write (`hook.ts` runs fresh per turn\n * anyway, and this is a handful of file reads/`includes` checks), so\n * callers should prefer this over `webviewPatchedEditors` for the\n * link-vs-plain decision itself; `webviewPatchedEditors` remains useful for\n * `extension.ts`'s own \"did I just newly patch something, should I prompt a\n * reload\" transition-detection, which is a different question.\n */\nexport function isCurrentlyPatched(editorFolder: string): boolean {\n\treturn findClaudeCodeWebviewFiles()\n\t\t.filter((f) => f.editorFolder === editorFolder)\n\t\t.some((f) => {\n\t\t\ttry {\n\t\t\t\treturn readFileSync(f.filePath, \"utf8\").includes(_VERSION_TAG);\n\t\t\t} catch {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n}\n\nexport type TPatchSummary = {\n\tpatched: number;\n\tskipped: number;\n\tfailed: number;\n\t/** Editor-folder names (\"Cursor\"/\"Code\"/\"VSCodium\") whose webview is\n\t * actually patched right now -- the only editors it's safe to send a\n\t * link-encoded spinner verb to. An editor missing from this list must get\n\t * plain text, even if some *other* editor on the same machine patched\n\t * fine: each editor updates Claude Code independently, so patch success\n\t * is never all-or-nothing across a machine. */\n\tpatchedFolders: string[];\n};\n\nexport function applyToAllInstalled(): TPatchSummary {\n\tconst summary: TPatchSummary = {\n\t\tpatched: 0,\n\t\tskipped: 0,\n\t\tfailed: 0,\n\t\tpatchedFolders: [],\n\t};\n\tfor (const { editorFolder, filePath } of findClaudeCodeWebviewFiles()) {\n\t\tconst result = patchFile(filePath);\n\t\tif (result === \"patched\" || result === \"already-patched\") {\n\t\t\tsummary.patched++;\n\t\t\tif (!summary.patchedFolders.includes(editorFolder)) {\n\t\t\t\tsummary.patchedFolders.push(editorFolder);\n\t\t\t}\n\t\t} else if (result === \"no-match\") summary.skipped++;\n\t\telse summary.failed++;\n\t}\n\treturn summary;\n}\n\nexport function restoreAllInstalled(): number {\n\tlet restored = 0;\n\tfor (const { filePath } of findClaudeCodeWebviewFiles()) {\n\t\tif (restoreFile(filePath)) restored++;\n\t}\n\treturn restored;\n}\n","import type { TAd } from \"./types\";\nimport { encodeLinkedVerb } from \"./webviewPatch\";\n\n// Built via fromCharCode rather than escape-sequence literals in source:\n// this file has previously been bitten by literal ESC/BEL control bytes\n// silently landing in the source text instead of the intended two-character\n// escape sequences -- fromCharCode sidesteps that entirely.\nconst _ESC = String.fromCharCode(27);\nconst _DIM = `${_ESC}[2m`;\nconst _RESET = `${_ESC}[0m`;\n\n/** One-line ad copy shared by every surface -- \"brand: text\" if a brand name\n * is present, otherwise just the text. */\nexport function adLine(ad: TAd): string {\n\tconst text = ad.adText.trim();\n\treturn ad.brandName ? `${ad.brandName}: ${text}` : text;\n}\n\n/** The ad's own title when the server sent one -- shorter and more\n * recognizable than `adLine()`'s brand+body combo. Falls back to `adLine()`\n * for an ad with no `title` at all. */\nexport function adTitle(ad: TAd): string {\n\treturn ad.title?.trim() || adLine(ad);\n}\n\n/** \"name: body\" -- the ad's own title (not `brandName`) paired with its body\n * copy, what `spinnerVerb()` wraps in brackets. Falls back to the bare body\n * for an ad with no `title` at all, same fallback shape as `adTitle()`. */\nexport function adNameLine(ad: TAd): string {\n\tconst name = ad.title?.trim();\n\tconst body = ad.adText.trim();\n\treturn name ? `${name}: ${body}` : body;\n}\n\n/**\n * The spinner pads to `max(verbLength) + 3`, so one long verb widens the\n * whole spinner region. Keeps well under Claude Code's own longest built-in\n * verbs. Prefers a word boundary, but only backs off to one when doing so\n * doesn't waste more than a few characters of the budget -- otherwise a\n * short first word (e.g. \"Acme\") would truncate far short of the limit.\n */\nexport function truncate(text: string, maxLength: number): string {\n\tif (text.length <= maxLength) return text;\n\tconst hardCut = text.slice(0, maxLength - 1);\n\tconst lastSpace = hardCut.lastIndexOf(\" \");\n\tconst wastedByBackingOff = hardCut.length - lastSpace;\n\tconst cut =\n\t\tlastSpace > 0 && wastedByBackingOff <= 6\n\t\t\t? hardCut.slice(0, lastSpace)\n\t\t\t: hardCut;\n\treturn `${cut.trimEnd()}…`;\n}\n\n/**\n * Briefly dropped to 32 to \"fix\" clipped ad copy. That was wrong and is\n * reverted: the label length was never the problem. Claude Code sizes the\n * spinner region from `max(verbLength) + 3` -- the RAW verb string, which for\n * the extension's link-encoded form is label + SOH + tracking URL + SOH +\n * base64 logo. Measured live: 7,126 characters total, of which the label was\n * 26. Truncating the label shrinks 26 of 7,126 and changes nothing about the\n * broken layout; it just costs advertisers their copy. The real fix is\n * shrinking the *payload* (see `logoCache.ts`'s `_MAX_BYTES`).\n */\nconst _SPINNER_MAX = 60;\nconst _SPINNER_PREFIX = \"[\";\nconst _SPINNER_SUFFIX = \"]\";\n\n/**\n * What the spinner shows between \"a turn started\" and \"this turn's ad\n * resolved\". Deliberately an explicit value, never `undefined`/key-deletion:\n * removing `claudeCode.spinnerVerbs` from settings.json does NOT visibly\n * reset the panel -- Claude Code's webview keeps the last verbs it read in\n * memory and only re-renders on a *new* value, so a delete left the previous\n * turn's ad on screen for the entire fetch (confirmed live: 4.7s between\n * `hook.ts` clearing at turn start and the real ad landing, with the old ad\n * visible the whole time). Writing Claude's own style of verb explicitly is\n * what actually replaces it, and matches the request to fall back to\n * Claude's own thinking text rather than any \"Sponsored\"-branded placeholder.\n */\nexport const RESET_VERBS = [\"Thinking…\"];\n\n/**\n * \"[<name>: <body>]\" — reads unmistakably as an ad in place of\n * \"Discombobulating…\", and the brackets keep it visually distinct from\n * Claude's own status text either side of it. No \"KILI AD:\" label -- just\n * the ad's own name paired with its body copy (`adNameLine()`), the text an\n * advertiser actually wrote on the campaign form. Still truncates as a last\n * resort so the closing bracket is never cut off.\n *\n * Never clickable as plain text -- confirmed by reading the shipped webview\n * bundle: the verb string is normally rendered straight into a React\n * `<span>`'s `children`, with no markdown/link parsing anywhere in that\n * path. Use this for the CLI terminal spinner (a real TTY, no way around\n * it) and as the plain-text fallback for the extension spinner. For the\n * extension spinner specifically, prefer `spinnerVerbLink()` below --\n * `webviewPatch.ts` patches that one `<span>` to understand it.\n */\nexport function spinnerVerb(ad: TAd): string {\n\tconst budget = _SPINNER_MAX - _SPINNER_PREFIX.length - _SPINNER_SUFFIX.length;\n\tconst body = truncate(adNameLine(ad), Math.max(10, budget));\n\treturn `${_SPINNER_PREFIX}${body}${_SPINNER_SUFFIX}`;\n}\n\n/**\n * The extension spinner's clickable form -- same visible text as\n * `spinnerVerb()`, but encoded (via `encodeLinkedVerb`) for the patch\n * installed by `webviewPatch.ts` to unpack into a real `<a href>`.\n *\n * Only ever call this when the patch is confirmed applied\n * (`config.webviewPatched`). Without the patch, nothing understands the\n * encoding: the unmodified renderer just prints the whole raw string,\n * including the url, in plain view -- not a graceful degradation, an\n * actual regression back to the `[[label]](url)` mess this package shipped\n * once already. `refresh.ts` is what gates this; this function doesn't\n * check the flag itself, since it has no way to read it.\n *\n * `logoDataUri` overrides `ad.favicon` -- the chat panel webview's CSP\n * (`img-src 'self' https://*.vscode-cdn.net data:`, confirmed via its own\n * DevTools console) blocks loading `ad.favicon`'s raw remote URL entirely,\n * so `refresh.ts` resolves it to a cached `data:` URI (see `logoCache.ts`)\n * before calling this. Passing nothing here falls back to the raw URL,\n * which is only ever correct for a caller that doesn't need it to actually\n * render as an image (none currently do -- kept as a fallback, not a path\n * anything exercises).\n */\nexport function spinnerVerbLink(ad: TAd, logoDataUri?: string | null): string {\n\tconst verb = spinnerVerb(ad);\n\t// `undefined` (param omitted) means \"no resolution attempted, use\n\t// ad.favicon as-is\" -- `null` (param explicitly passed) means \"resolution\n\t// was attempted and came back empty, omit the logo entirely\" rather than\n\t// falling back to the raw URL that's the whole reason this override\n\t// exists. `??` would collapse those two cases together; this doesn't.\n\tconst logo =\n\t\tlogoDataUri === undefined ? ad.favicon : (logoDataUri ?? undefined);\n\treturn ad.clickUrl ? encodeLinkedVerb(verb, ad.clickUrl, logo) : verb;\n}\n\nexport function dim(text: string): string {\n\treturn `${_DIM}${text}${_RESET}`;\n}\n","import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { readJsonOwnedByUser, writeJsonAtomic } from \"./store\";\nimport { isCurrentlyPatched } from \"./webviewPatch\";\n\n/** Every editor identity this module knows how to locate. `hook.ts` (a\n * plain Node process with no `vscode` API, so no `vscode.env.appName` to\n * read) uses this to update whichever ones are actually installed, rather\n * than needing to know which editor is running Claude Code's chat panel. */\nconst _KNOWN_APP_NAMES = [\"Cursor\", \"Visual Studio Code\", \"VSCodium\"];\n\n/**\n * `vscode.workspace.getConfiguration(\"claudeCode\").update(...)` silently\n * no-ops for `spinnerVerbs`: it's not declared in any extension's\n * `contributes.configuration`, and VS Code's Configuration API only\n * reliably persists keys under a namespace some extension owns (ours works\n * fine for `kili.*`, which we do declare). So for this one undocumented,\n * cross-extension key, write the editor's own `settings.json` directly --\n * merge-only, same discipline as `claude/settings.ts` uses for\n * `~/.claude/settings.json`.\n */\n\nfunction _userSettingsFolder(appName: string): string | null {\n\tconst lower = appName.toLowerCase();\n\tif (lower.includes(\"cursor\")) return \"Cursor\";\n\tif (lower.includes(\"vscodium\")) return \"VSCodium\";\n\tif (lower.includes(\"visual studio code\") || lower.includes(\"code\"))\n\t\treturn \"Code\";\n\treturn null;\n}\n\nexport function editorSettingsPath(appName: string): string | null {\n\tconst folder = _userSettingsFolder(appName);\n\tif (!folder) return null;\n\tconst home = homedir();\n\tswitch (process.platform) {\n\t\tcase \"win32\": {\n\t\t\tconst appData = process.env.APPDATA ?? join(home, \"AppData\", \"Roaming\");\n\t\t\treturn join(appData, folder, \"User\", \"settings.json\");\n\t\t}\n\t\tcase \"darwin\":\n\t\t\treturn join(\n\t\t\t\thome,\n\t\t\t\t\"Library\",\n\t\t\t\t\"Application Support\",\n\t\t\t\tfolder,\n\t\t\t\t\"User\",\n\t\t\t\t\"settings.json\",\n\t\t\t);\n\t\tdefault:\n\t\t\treturn join(\n\t\t\t\tprocess.env.XDG_CONFIG_HOME ?? join(home, \".config\"),\n\t\t\t\tfolder,\n\t\t\t\t\"User\",\n\t\t\t\t\"settings.json\",\n\t\t\t);\n\t}\n}\n\n/**\n * Reads via `readJsonOwnedByUser`, not `readJson` -- this is the editor's own\n * `settings.json`, the file that also holds the user's theme, activity bar\n * layout, and everything else. VS Code accepts JSONC comments/trailing\n * commas there, which `JSON.parse` can't, and treating a parse failure as\n * \"empty\" here means a merge-write silently discards all of it, keeping only\n * `claudeCode.spinnerVerbs` -- confirmed: this happened for real, on a file\n * this function is called against on *every single turn* via `hook.ts`.\n * Throws `SettingsParseError` on a genuinely unparseable existing file;\n * callers must catch and skip, never let it silently wipe the file.\n */\nexport function writeClaudeCodeSpinnerVerbs(\n\tappName: string,\n\tverbs: string[] | undefined,\n): boolean {\n\tconst path = editorSettingsPath(appName);\n\tif (!path) return false;\n\tconst current = readJsonOwnedByUser<Record<string, unknown>>(path, {});\n\t// Same object shape as the CLI's `spinnerVerbs` in ~/.claude/settings.json\n\t// ({mode, verbs}), not a bare array -- Claude Code's webview does\n\t// `for (const v of value.verbs)` and crashes (\"e.verbs is not iterable\")\n\t// on a bare array, since `value.verbs` is then undefined. Confirmed the\n\t// hard way against a live Cursor install.\n\t//\n\t// JSON.stringify drops an undefined-valued key, so assigning `undefined`\n\t// here has the same on-disk effect as deleting it.\n\tconst next = {\n\t\t...current,\n\t\t\"claudeCode.spinnerVerbs\":\n\t\t\tverbs === undefined ? undefined : { mode: \"replace\", verbs },\n\t};\n\twriteJsonAtomic(path, next);\n\treturn true;\n}\n\n/**\n * Same write, but for every editor actually installed on this machine\n * (detected by its settings.json already existing) rather than one named\n * editor. `hook.ts` calls this on every `UserPromptSubmit` so the chat-panel\n * spinner refreshes per-turn, the same as the terminal spinner -- the\n * extension's own 60s timer alone left it looking stuck across turns inside\n * that window.\n *\n * Takes both a plain and a link-encoded verb rather than one pre-decided\n * value: which one is safe to send is a per-editor question, not a\n * machine-wide one. `patchedEditorFolders` names exactly the editors (by the\n * same \"Cursor\"/\"Code\"/\"VSCodium\" folder name `_userSettingsFolder` returns)\n * whose Claude Code webview is actually patched to decode the link encoding\n * -- every other editor gets the plain verb, even if some other editor on\n * this same machine patched fine. Sending the link form to an unpatched\n * editor doesn't degrade gracefully, it leaks the raw SOH-separated url as\n * visible garbage text (confirmed live, before this per-editor split\n * existed -- see `TPatchSummary.patchedFolders`'s doc comment).\n */\n/**\n * Clears `kili.apiKey` in every editor actually installed on this machine,\n * not just the one running this extension process right now -- `_handleSignOut`\n * in `extension.ts` still separately calls `vscode.workspace.getConfiguration\n * (\"kili\").update(\"apiKey\", \"\", Global)` for the *current* editor (so that\n * editor's own UI reacts live via `onDidChangeConfiguration`, which a direct\n * file write can't trigger), but that call is scoped to the editor process\n * this code happens to be running inside -- it has no way to reach a\n * *different* installed editor's settings.json. Without this, signing out\n * in Cursor left VS Code's own copy of the key untouched, and worse: VS\n * Code's next activation/config-sync would read that still-present key and\n * write it right back into the shared `~/.kili/config.json` cache, silently\n * undoing the sign-out. Confirmed live.\n *\n * Same merge-only, JSONC-safe discipline as\n * `writeClaudeCodeSpinnerVerbsEverywhereInstalled` -- one editor's\n * unparseable `settings.json` must not block clearing a different, valid\n * one.\n */\nexport function clearKiliApiKeyEverywhereInstalled(): void {\n\tfor (const appName of _KNOWN_APP_NAMES) {\n\t\tconst path = editorSettingsPath(appName);\n\t\tif (!path || !existsSync(path)) continue;\n\t\ttry {\n\t\t\tconst current = readJsonOwnedByUser<Record<string, unknown>>(path, {});\n\t\t\tif (!(\"kili.apiKey\" in current) || current[\"kili.apiKey\"] === \"\") {\n\t\t\t\tcontinue; // nothing to clear, avoid a no-op write/mtime bump\n\t\t\t}\n\t\t\twriteJsonAtomic(path, { ...current, \"kili.apiKey\": \"\" });\n\t\t} catch {\n\t\t\t// See writeClaudeCodeSpinnerVerbs's doc comment: an unparseable\n\t\t\t// settings.json for one editor must not block clearing another.\n\t\t}\n\t}\n}\n\n/**\n * No `patchedEditorFolders` parameter -- deliberately dropped in favor of\n * `webviewPatch.ts`'s `isCurrentlyPatched()`, a live, on-disk check, not a\n * cached flag from whenever this extension last activated. A cached list\n * goes stale the moment Claude Code auto-updates itself in between\n * activations (a version bump ships a brand new, unpatched webview bundle\n * under a new `anthropic.claude-code-<version>` folder) -- this used to keep\n * sending the link-encoded verb to an editor the cache still believed was\n * patched, which rendered as visible raw `[label]url` garbage text instead\n * of a link. Confirmed live.\n */\nexport function writeClaudeCodeSpinnerVerbsEverywhereInstalled(\n\tplainVerbs: string[] | undefined,\n\tlinkVerbs: string[] | undefined,\n): void {\n\tfor (const appName of _KNOWN_APP_NAMES) {\n\t\tconst path = editorSettingsPath(appName);\n\t\tif (!path || !existsSync(path)) continue;\n\t\tconst folder = _userSettingsFolder(appName);\n\t\tconst isPatched = folder !== null && isCurrentlyPatched(folder);\n\t\ttry {\n\t\t\twriteClaudeCodeSpinnerVerbs(appName, isPatched ? linkVerbs : plainVerbs);\n\t\t} catch {\n\t\t\t// One editor's unparseable settings.json must not block updating a\n\t\t\t// different, valid one -- see writeClaudeCodeSpinnerVerbs's doc comment.\n\t\t}\n\t}\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { claudeSettingsPath, settingsBackupPath } from \"../core/paths\";\nimport { readJson, readJsonOwnedByUser, writeJsonAtomic } from \"../core/store\";\n\n/**\n * Exactly the top-level keys `enable`/`disable` are allowed to touch in\n * `~/.claude/settings.json` -- a shared, user-owned file that may already\n * hold `mcpServers` and other config we must never rewrite wholesale.\n */\nconst OWNED_KEYS = [\n\t\"spinnerVerbs\",\n\t\"spinnerTipsOverride\",\n\t\"statusLine\",\n] as const;\n\n/** Our two hook entries, matched by this marker inside each command string\n * so `disable()` can remove precisely the ones we added even if the user's\n * `hooks` block also has entries of their own for the same events. */\nconst _HOOK_MARKER = \"__kili_hook__\";\nconst OWNED_HOOK_EVENTS = [\"UserPromptSubmit\", \"Stop\"] as const;\n\nexport type TClaudeSettings = Record<string, unknown> & {\n\thooks?: Record<string, unknown[]>;\n};\n\n/**\n * Copies the file byte-for-byte, not parse-then-restringify -- a backup's\n * whole job is to be restorable later, so it must work even when the file\n * has JSONC comments `JSON.parse` can't handle (round-tripping through\n * `JSON.stringify` would silently drop them from the backup too). No-ops if\n * the file doesn't exist yet -- nothing to back up.\n */\nexport function backupOnce(): void {\n\tconst backupPath = settingsBackupPath();\n\tif (existsSync(backupPath)) return;\n\tconst settingsPath = claudeSettingsPath();\n\tif (!existsSync(settingsPath)) return;\n\tmkdirSync(dirname(backupPath), { recursive: true });\n\twriteFileSync(backupPath, readFileSync(settingsPath, \"utf8\"), \"utf8\");\n}\n\n/**\n * All three of `enable`/`updateSpinnerVerb`/`disable` read via\n * `readJsonOwnedByUser`, not `readJson` -- this file is the user's own,\n * commonly hand-edited with JSONC comments `JSON.parse` can't handle. Letting\n * a parse failure fall through to `writeJsonAtomic` as if the file were empty\n * would silently discard everything else in it (confirmed: this happened for\n * real). Callers (`extension.ts`) must catch `SettingsParseError` and warn\n * instead of writing, not let it crash outright.\n */\nexport function enable(hookBinPath: string): void {\n\tbackupOnce();\n\tconst settings = readJsonOwnedByUser<TClaudeSettings>(\n\t\tclaudeSettingsPath(),\n\t\t{},\n\t);\n\n\tsettings.spinnerVerbs = { mode: \"replace\", verbs: [\"Sponsored\"] };\n\t// `statusLine` is still configured -- `statusline.js` running at all\n\t// (regardless of what it prints) is `isTerminalActive`'s only signal that\n\t// a real terminal, not the IDE chat panel, is currently in front of the\n\t// user; removing this entirely would silently break that and misattribute\n\t// every terminal turn's impression to the extension surface instead. What\n\t// it prints changed instead -- see `statusline.ts`: it no longer renders\n\t// the ad (a second one below the loader/spinner was redundant on the same\n\t// screen and got turned off by request), only Claude's own hints.\n\tsettings.statusLine = {\n\t\ttype: \"command\",\n\t\t// Must actually invoke node -- a bare path relies on the OS resolving\n\t\t// a shebang / file association for a plain .js file, which Windows\n\t\t// never does at all and which isn't guaranteed elsewhere either. The\n\t\t// hook entries below already get this right (`node \"${path}\" ...`);\n\t\t// this one silently didn't, so the status line never ran.\n\t\tcommand: `node \"${hookBinPath.replace(\"hook.js\", \"statusline.js\")}\"`,\n\t};\n\n\tsettings.hooks = _mergeHooks(settings.hooks ?? {}, hookBinPath);\n\n\twriteJsonAtomic(claudeSettingsPath(), settings);\n}\n\n/**\n * Called from `hook.ts` on every `UserPromptSubmit` once a fresh ad has been\n * fetched -- swaps the spinner's word for that ad's copy. Only touches\n * `spinnerVerbs`; `statusLine` and `hooks` are left exactly as `enable()`\n * set them, so this is safe to call every turn without re-merging hooks.\n */\nexport function updateSpinnerVerb(verb: string): void {\n\tconst settings = readJsonOwnedByUser<TClaudeSettings>(\n\t\tclaudeSettingsPath(),\n\t\t{},\n\t);\n\tsettings.spinnerVerbs = { mode: \"replace\", verbs: [verb] };\n\twriteJsonAtomic(claudeSettingsPath(), settings);\n}\n\nexport function disable(): void {\n\tconst settings = readJsonOwnedByUser<TClaudeSettings>(\n\t\tclaudeSettingsPath(),\n\t\t{},\n\t);\n\n\tfor (const key of OWNED_KEYS) {\n\t\tdelete (settings as Record<string, unknown>)[key];\n\t}\n\n\tif (settings.hooks) {\n\t\tfor (const event of OWNED_HOOK_EVENTS) {\n\t\t\tconst entries = settings.hooks[event];\n\t\t\tif (!Array.isArray(entries)) continue;\n\t\t\tconst kept = entries.filter((entry) => !_isOwnedHookEntry(entry));\n\t\t\tif (kept.length > 0) {\n\t\t\t\tsettings.hooks[event] = kept;\n\t\t\t} else {\n\t\t\t\tdelete settings.hooks[event];\n\t\t\t}\n\t\t}\n\t\tif (Object.keys(settings.hooks).length === 0) {\n\t\t\t// JSON.stringify drops undefined-valued keys, so this has the same\n\t\t\t// on-disk effect as `delete` without biome's no-delete warning.\n\t\t\tsettings.hooks = undefined;\n\t\t}\n\t}\n\n\twriteJsonAtomic(claudeSettingsPath(), settings);\n}\n\n/** Detects the one setting that silently disables hooks (and therefore\n * `statusLine`) so callers can degrade to spinner-verbs-only and say so. */\nexport function hooksDisabled(): boolean {\n\tconst settings = readJson<TClaudeSettings>(claudeSettingsPath(), {});\n\treturn settings.disableAllHooks === true;\n}\n\nfunction _mergeHooks(\n\thooks: Record<string, unknown[]>,\n\thookBinPath: string,\n): Record<string, unknown[]> {\n\tconst next = { ...hooks };\n\tfor (const event of OWNED_HOOK_EVENTS) {\n\t\tconst existing = (next[event] ?? []).filter(\n\t\t\t(entry) => !_isOwnedHookEntry(entry),\n\t\t);\n\t\tnext[event] = [\n\t\t\t...existing,\n\t\t\t{\n\t\t\t\tmatcher: \"*\",\n\t\t\t\thooks: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"command\",\n\t\t\t\t\t\tcommand: `node \"${hookBinPath}\" ${event} ${_HOOK_MARKER}`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t];\n\t}\n\treturn next;\n}\n\nfunction _isOwnedHookEntry(entry: unknown): boolean {\n\treturn JSON.stringify(entry).includes(_HOOK_MARKER);\n}\n","import { debugLog } from \"./debug\";\nimport { logoCachePath } from \"./paths\";\nimport { readJson, writeJsonAtomic } from \"./store\";\n\n/**\n * Turns a remote logo URL into a `data:` URI, cached on disk keyed by the\n * original URL -- fetched at most once per URL, ever.\n *\n * Why this exists at all: the chat-panel webview's Content-Security-Policy\n * only allows `img-src 'self' https://*.vscode-cdn.net data:` -- confirmed\n * live via the webview's own DevTools console, which showed the exact CSP\n * violation for a raw `https://pbs.twimg.com/...` logo URL. No amount of\n * patching the render function gets around that; it's Chromium's own policy\n * for the webview, enforced independently of anything this extension writes.\n * `data:` URIs are the one exception CSP explicitly allows, so the fix is to\n * embed the image bytes directly instead of linking to them.\n */\n\ntype TLogoCache = Record<string, string>;\n\nconst _FETCH_TIMEOUT_MS = 3000;\n/**\n * Base64 inflates size by ~33%, and this ends up embedded in\n * `~/.claude/settings.json` / `claudeCode.spinnerVerbs` -- both real files a\n * user might open. Capped well under any practical settings-file size limit;\n * an oversized source image just doesn't get a logo, same as a fetch failure.\n *\n * Briefly lowered to 2_000 on the theory that this payload was inflating the\n * chat panel's spinner width and causing the clipped/overlapping ad text.\n * That was wrong, and the cost was real (most advertiser logos fell back to\n * the generic bundled badge). The panel computes its width as\n * `Math.max(...verbs.map(v => v.length))` over the list AFTER\n * `webviewPatch.ts`'s patch has already split each entry into its label --\n * so the width only ever sees the ~26-character label, never the URL or this\n * logo. The actual cause was stale render state in that component; see the\n * `_ANCHORS` doc comment. Restored, so real advertiser logos show again.\n */\nconst _MAX_BYTES = 100_000;\n\n/**\n * Bundled at build time, not fetched -- a tiny vector redraw of the\n * extension's own icon (`assets/icon.png`'s 3x3 grid mark, one cell\n * highlighted), not the raw PNG. Kept as hand-drawn SVG rather than a\n * base64 copy of the real asset for the same reason the old \"K\" badge this\n * replaced was SVG too: this string ends up embedded directly in\n * `claudeCode.spinnerVerbs` inside `~/.claude/settings.json` -- a real file\n * a user might open -- and a ~180-byte vector shape stays negligible there\n * where a base64'd raster (icon.png is ~45KB, ~60KB again once base64\n * inflates it) would not. `data:image/svg+xml` is covered by the same CSP\n * allowance as a base64 raster image, so this needs no network round trip\n * and can never violate the policy that blocked the raw URL in the first\n * place.\n */\nexport const KILI_FALLBACK_LOGO_DATA_URI = `data:image/svg+xml,${encodeURIComponent(\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\"><rect width=\"14\" height=\"14\" rx=\"3\" fill=\"#000\"/>' +\n\t\t'<rect x=\"2\" y=\"2\" width=\"3\" height=\"3\" rx=\"0.6\" fill=\"#D1D5DB\"/>' +\n\t\t'<rect x=\"6\" y=\"2\" width=\"3\" height=\"3\" rx=\"0.6\" fill=\"#D1D5DB\"/>' +\n\t\t'<rect x=\"10\" y=\"2\" width=\"3\" height=\"3\" rx=\"0.6\" fill=\"#22C55E\"/>' +\n\t\t'<rect x=\"2\" y=\"6\" width=\"3\" height=\"3\" rx=\"0.6\" fill=\"#D1D5DB\"/>' +\n\t\t'<rect x=\"6\" y=\"6\" width=\"3\" height=\"3\" rx=\"0.6\" fill=\"#D1D5DB\"/>' +\n\t\t'<rect x=\"10\" y=\"6\" width=\"3\" height=\"3\" rx=\"0.6\" fill=\"#D1D5DB\"/>' +\n\t\t'<rect x=\"2\" y=\"10\" width=\"3\" height=\"3\" rx=\"0.6\" fill=\"#D1D5DB\"/>' +\n\t\t'<rect x=\"6\" y=\"10\" width=\"3\" height=\"3\" rx=\"0.6\" fill=\"#D1D5DB\"/>' +\n\t\t'<rect x=\"10\" y=\"10\" width=\"3\" height=\"3\" rx=\"0.6\" fill=\"#D1D5DB\"/></svg>',\n)}`;\n\nexport function getCachedLogoDataUri(url: string): string | null {\n\tconst cache = readJson<TLogoCache>(logoCachePath(), {});\n\treturn cache[url] ?? null;\n}\n\n/**\n * The logo to actually put in a spinner verb right now, synchronously: the\n * cached real logo if `fetchAndCacheLogoDataUri` already resolved it, the\n * bundled fallback badge otherwise -- never the raw blocked URL, and never\n * nothing (a `Sponsored`-only line with no mark at all reads as less\n * trustworthy than a generic badge, the same reasoning kickbacks.ai's own\n * fallback badge is built on). Callers still need to separately call\n * `fetchAndCacheLogoDataUri` (fire-and-forget) so a later turn can upgrade\n * from the fallback to the real logo once it's cached.\n */\nexport function resolveLogoDataUri(favicon: string | undefined): string {\n\tif (!favicon) return KILI_FALLBACK_LOGO_DATA_URI;\n\treturn getCachedLogoDataUri(favicon) ?? KILI_FALLBACK_LOGO_DATA_URI;\n}\n\n/**\n * Fetches and caches in the background -- never awaited by a caller on the\n * per-turn critical path. Callers should render without a logo on the turn\n * that first sees a new URL, then pick it up from `getCachedLogoDataUri` on\n * a later turn once this has had a chance to complete.\n */\nexport async function fetchAndCacheLogoDataUri(\n\turl: string,\n): Promise<string | null> {\n\tconst cached = getCachedLogoDataUri(url);\n\tif (cached) return cached;\n\n\tconst controller = new AbortController();\n\tconst timer = setTimeout(() => controller.abort(), _FETCH_TIMEOUT_MS);\n\ttry {\n\t\tconst res = await fetch(url, { signal: controller.signal });\n\t\tif (!res.ok) {\n\t\t\tdebugLog(\"logoCache: fetch not ok\", url, res.status);\n\t\t\treturn null;\n\t\t}\n\t\tconst contentType = res.headers.get(\"content-type\") ?? \"image/png\";\n\t\tif (!contentType.startsWith(\"image/\")) {\n\t\t\tdebugLog(\"logoCache: non-image content-type\", url, contentType);\n\t\t\treturn null;\n\t\t}\n\t\tconst buf = await res.arrayBuffer();\n\t\tif (buf.byteLength > _MAX_BYTES) {\n\t\t\tdebugLog(\"logoCache: oversized\", url, buf.byteLength, \"> \", _MAX_BYTES);\n\t\t\treturn null;\n\t\t}\n\t\tconst dataUri = `data:${contentType};base64,${Buffer.from(buf).toString(\"base64\")}`;\n\t\tconst cache = readJson<TLogoCache>(logoCachePath(), {});\n\t\tcache[url] = dataUri;\n\t\twriteJsonAtomic(logoCachePath(), cache);\n\t\tdebugLog(\"logoCache: cached\", url, buf.byteLength, \"bytes\");\n\t\treturn dataUri;\n\t} catch (e) {\n\t\t// A dead/slow/oversized logo URL must never block or fail the ad\n\t\t// itself -- the label and click-through still work with no logo.\n\t\tdebugLog(\"logoCache: fetch threw\", url, e instanceof Error ? e.message : e);\n\t\treturn null;\n\t} finally {\n\t\tclearTimeout(timer);\n\t}\n}\n","import { updateSpinnerVerb } from \"../claude/settings\";\r\nimport { putAd } from \"./cache\";\r\nimport { KiliClient } from \"./client\";\r\nimport { PLACEMENT } from \"./constants\";\r\nimport { spinnerVerb, spinnerVerbLink } from \"./copy\";\r\nimport { debugLog } from \"./debug\";\r\nimport { writeClaudeCodeSpinnerVerbsEverywhereInstalled } from \"./editorSettings\";\r\nimport { fetchAndCacheLogoDataUri, resolveLogoDataUri } from \"./logoCache\";\r\nimport type { TAd, TRuntimeConfig } from \"./types\";\r\n\r\n// `PLACEMENT.TERMINAL_STATUSLINE` deliberately excluded from every group\r\n// below: `claude/settings.ts`'s `enable()` and `terminal.ts`'s\r\n// `enableTerminalHooks()` no longer set `statusLine` at all (a second ad\r\n// below the loader/spinner on the same screen, turned off by request), so\r\n// nothing can ever render that placement -- requesting it would only serve\r\n// (and risk billing) an ad no one sees.\r\nconst _ALL_PLACEMENTS: string[] = [\r\n\tPLACEMENT.TERMINAL_SPINNER,\r\n\tPLACEMENT.EXTENSION_SPINNER,\r\n\tPLACEMENT.EXTENSION_STATUSBAR,\r\n];\r\n\r\n/** `hook.ts`'s group -- the surface driven by real per-turn context. */\r\nexport const TERMINAL_PLACEMENTS: string[] = [PLACEMENT.TERMINAL_SPINNER];\r\n\r\n/** `extension.ts`'s idle-timer group -- the two surfaces it renders itself. */\r\nexport const EXTENSION_PLACEMENTS: string[] = [\r\n\tPLACEMENT.EXTENSION_SPINNER,\r\n\tPLACEMENT.EXTENSION_STATUSBAR,\r\n];\r\n\r\n/**\r\n * Fetches every eligible ad for the given surfaces in a single `/ads` call.\r\n *\r\n * Requesting a group of surfaces together, instead of as independent calls,\r\n * is what guarantees they resolve to the same server response rather than\r\n * two separate calls landing on two different picks (relevant whenever\r\n * `AllAdServeStrategy` is configured server-side and returns a shuffled\r\n * multi-ad list; under the currently-configured `RandomAdServeStrategy` each\r\n * call just returns one ad per placement, but the grouping stays correct\r\n * either way).\r\n *\r\n * Callers must pass only the placements *they* own -- `hook.ts` (terminal\r\n * spinner + terminal statusline) and `extension.ts` (extension spinner +\r\n * extension statusbar) must never share a call, even though this function is\r\n * happy to serve either group. They used to always request all four\r\n * together: `hook.ts` ran once per turn, `extension.ts`'s idle timer ran\r\n * every 60s, regardless of whether a turn was even in flight. Because both\r\n * calls wrote into the same cache/settings for all four placements, the idle\r\n * call would periodically stomp the terminal placements back to whatever ad\r\n * the server resolved -- visibly a *different*, seemingly-stuck ad on the\r\n * terminal status line while the loader/spinner (driven by the real per-turn\r\n * call) kept updating normally. Confirmed live: this was happening in prod.\r\n *\r\n * No `messages` param, deliberately: api.kili's ad selection never reads\r\n * conversation content (`RandomAdServeStrategy`/`AllAdServeStrategy` and the\r\n * `IAdServeStrategy` interface itself only ever see `candidates`), so this\r\n * used to send real chat text over the wire for nothing -- see `client.ts`'s\r\n * `_body()`.\r\n *\r\n * Only the *first* ad in each placement's set gets applied here (written to\r\n * the cache, and to `claudeCode.spinnerVerbs` for the extension spinner) --\r\n * under `RandomAdServeStrategy` that's the only ad there is anyway. A turn\r\n * shows exactly this one ad until the next real fetch replaces it: either\r\n * `hook.ts`'s next `UserPromptSubmit` (terminal), or `extension.ts`'s\r\n * turn-start fetch (extension surfaces) -- see that file's doc comments for\r\n * why there is no client-side rotation between real fetches anymore.\r\n *\r\n * Callable from both `hook.ts` (a plain Node process with no `vscode` API)\r\n * and `extension.ts` -- everything here is a file write or a network call,\r\n * nothing needs the extension host. `extension.ts` additionally pushes the\r\n * result into its own status bar item after calling this.\r\n */\r\nexport async function refreshAllPlacements(\r\n\tconfig: TRuntimeConfig,\r\n\tsessionId: string,\r\n\tplacementIds: string[] = _ALL_PLACEMENTS,\r\n): Promise<Map<string, TAd[]>> {\r\n\tconst client = new KiliClient();\r\n\tconst adSets = await client.fetchAds({\r\n\t\tapiKey: config.apiKey,\r\n\t\tapiUrl: config.apiUrl,\r\n\t\tinstallId: config.installId,\r\n\t\tsessionId,\r\n\t\tplacementIds,\r\n\t});\r\n\r\n\t// One line per fetch, with what came back per placement -- the entry\r\n\t// point of the whole per-turn chain, so a `debug.log` read top-to-bottom\r\n\t// shows fetch -> write -> render without having to correlate file mtimes\r\n\t// across three processes by hand.\r\n\tdebugLog(\"refreshAllPlacements\", {\r\n\t\trequested: placementIds,\r\n\t\tgot: [...adSets].map(([id, ads]) => `${id}:${ads.length}`),\r\n\t\tsessionId,\r\n\t});\r\n\r\n\tfor (const [placementId, ads] of adSets) putAd(placementId, ads);\r\n\r\n\tconst terminalAds = adSets.get(PLACEMENT.TERMINAL_SPINNER);\r\n\tif (terminalAds?.[0]) updateSpinnerVerb(spinnerVerb(terminalAds[0]));\r\n\r\n\tconst extensionAds = adSets.get(PLACEMENT.EXTENSION_SPINNER);\r\n\tif (extensionAds?.[0]) applyExtensionSpinnerAd(extensionAds[0], config);\r\n\r\n\treturn adSets;\r\n}\r\n\r\n/** Both verb forms are always computed; which one a given editor actually\r\n * gets is decided per editor inside\r\n * `writeClaudeCodeSpinnerVerbsEverywhereInstalled`, from\r\n * `config.webviewPatchedEditors` -- see that function's doc comment for why\r\n * this can't be a single machine-wide decision (each editor updates Claude\r\n * Code independently, so patch success is too).\r\n *\r\n * Exported: `refreshAllPlacements` above calls this for the extension\r\n * spinner's first ad; `extension.ts`'s turn-start fetch is the other caller,\r\n * invoking `refreshAllPlacements` itself (which reaches this the same way)\r\n * every time a new turn's fetch resolves. */\r\nexport function applyExtensionSpinnerAd(ad: TAd, config: TRuntimeConfig): void {\r\n\t// `ad.favicon`'s raw URL is never usable directly -- the webview's CSP\r\n\t// blocks it outright (`img-src` has no allowance for arbitrary remote\r\n\t// hosts, confirmed live via the webview's own DevTools console). The\r\n\t// cached `data:` URI is the only form CSP actually permits; the bundled\r\n\t// badge covers every turn before that cache is warm. `void`: the fetch\r\n\t// runs in the background and must never delay or fail this turn's write --\r\n\t// a later turn upgrades from the fallback badge once it resolves.\r\n\tconst logo = resolveLogoDataUri(ad.favicon);\r\n\tif (ad.favicon) void fetchAndCacheLogoDataUri(ad.favicon);\r\n\r\n\tconst link = spinnerVerbLink(ad, logo);\r\n\t// KILI_DEBUG=1 only -- the last stop before this either lands as a\r\n\t// clickable, logo'd link in a patched webview, or falls back to plain\r\n\t// text. Confirms whether the ad this turn resolved even had a logo, and\r\n\t// whether any editor was actually patched to receive the encoded form.\r\n\tdebugLog(\"applyExtensionSpinnerAd\", {\r\n\t\tadId: ad.adId,\r\n\t\thasFavicon: Boolean(ad.favicon),\r\n\t\tfavicon: ad.favicon,\r\n\t\tusingFallbackBadge: logo.startsWith(\"data:image/svg+xml\"),\r\n\t\tencodedHasLogoSeparator: [...link].filter((c) => c.codePointAt(0) === 1)\r\n\t\t\t.length,\r\n\t\tpatchedEditors: config.webviewPatchedEditors,\r\n\t});\r\n\twriteClaudeCodeSpinnerVerbsEverywhereInstalled([spinnerVerb(ad)], [link]);\r\n}\r\n","#!/usr/bin/env node\nimport {\n\tisTerminalActive,\n\tsettlePendingTurn,\n\tstartPendingTurn,\n} from \"./core/cache\";\nimport { readRuntimeConfig, toSessionId } from \"./core/config\";\nimport { PLACEMENT } from \"./core/constants\";\nimport { RESET_VERBS } from \"./core/copy\";\nimport { debugLog } from \"./core/debug\";\nimport { writeClaudeCodeSpinnerVerbsEverywhereInstalled } from \"./core/editorSettings\";\nimport { TERMINAL_PLACEMENTS, refreshAllPlacements } from \"./core/refresh\";\n\n/**\n * `UserPromptSubmit` / `Stop` hook entry, run by Claude Code once per turn.\n *\n * MUST NEVER PRINT TO STDOUT. `UserPromptSubmit`'s stdout is injected into\n * the model's own context -- any ad copy printed here would be read by\n * Claude as if the user had typed it. Debug output goes to stderr only, and\n * only under `KILI_DEBUG=1`. Always exits 0: a broken ad fetch must never\n * block or fail a user's turn.\n */\nasync function main() {\n\tconst event = process.argv[2];\n\ttry {\n\t\tconst stdin = await _readStdin();\n\t\tconst payload = _parsePayload(stdin);\n\n\t\tif (event === \"UserPromptSubmit\") {\n\t\t\tawait _onUserPromptSubmit(payload);\n\t\t} else if (event === \"Stop\") {\n\t\t\tawait settlePendingTurn();\n\t\t\t_clearSpinnerAfterTurn();\n\t\t}\n\t} catch (error) {\n\t\tdebugLog(\"hook error\", event, error);\n\t}\n\tprocess.exit(0);\n}\n\n/**\n * Clears the finished turn's ad at `Stop`, so nothing stale is left behind\n * for the NEXT turn to flash on screen.\n *\n * The reset used to happen only at `UserPromptSubmit`, i.e. at the start of\n * the next turn. That is structurally too late: the spinner component mounts\n * and reads `claudeCode.spinnerVerbs` as the turn begins, and this hook\n * (a freshly spawned Node process) cannot write the new value before that\n * first read. So the previous ad was always shown for a moment, then\n * replaced -- exactly the reported \"shows the old ad for a little sec\".\n *\n * Clearing here instead means the setting already reads `RESET_VERBS` while\n * idle, so the next turn's very first render has nothing stale to show. This\n * costs nothing visually: the spinner is only rendered while Claude is\n * working, so between turns there is no visible surface to have cleared.\n * `UserPromptSubmit` still resets too, as a safety net for a turn whose\n * `Stop` never fired (interrupted, crashed, or a session that ended\n * mid-response).\n *\n * Impression billing is unaffected -- that already fired when the ad was\n * fetched and rendered, not here (see `claimCurrentImpression`).\n */\nfunction _clearSpinnerAfterTurn(): void {\n\tconst config = readRuntimeConfig();\n\tif (!config || !config.enabled) return;\n\tif (isTerminalActive()) return; // terminal draws its own verb, nothing to reset\n\twriteClaudeCodeSpinnerVerbsEverywhereInstalled(RESET_VERBS, RESET_VERBS);\n\tdebugLog(\"clearSpinnerAfterTurn: reset panel verb\");\n}\n\ntype TPayload = {\n\tsessionId: string | undefined;\n\tuserInput: string | undefined;\n};\n\nasync function _onUserPromptSubmit(payload: TPayload): Promise<void> {\n\tconst config = readRuntimeConfig();\n\tif (!config || !config.enabled) return;\n\n\tconst sessionId = toSessionId(payload.sessionId);\n\n\t// Exactly one spinner surface, never both. `UserPromptSubmit`/`Stop` fire\n\t// identically regardless of which UI is actually rendering this session,\n\t// so without this a single turn used to settle -- and bill -- an\n\t// impression for whichever surface *wasn't* even open, every time (see\n\t// `isTerminalActive`'s doc comment). Computed before the fetch below,\n\t// not after: the panel branch needs it immediately, to clear the previous\n\t// ad as early as possible (see the block right below).\n\tconst terminalActive = isTerminalActive();\n\n\t// IDE panel case only: clear `claudeCode.spinnerVerbs` synchronously,\n\t// before doing anything else -- this hook BLOCKS Claude Code's own turn\n\t// from starting until it exits, so this is the earliest point in the\n\t// entire turn lifecycle that can ever clear the previous turn's ad.\n\t// `extension.ts`'s own per-turn fetch (`_checkForNewTurn`) can't act this\n\t// fast: it's a long-running process decoupled from Claude Code's turn\n\t// lifecycle, polling `~/.kili/pending-turn.json` (which this function\n\t// writes, further below) up to `_TURN_POLL_INTERVAL_MS` late. Without\n\t// this write here, the previous turn's ad stayed visible for that whole\n\t// window -- confirmed live.\n\t//\n\t// Written as `RESET_VERBS` (\"Thinking…\"), NOT `undefined` -- see that\n\t// constant's doc comment: deleting `claudeCode.spinnerVerbs` does not\n\t// visibly reset the panel at all, because Claude Code's webview keeps the\n\t// last verbs it read in memory and only re-renders on a *new* value.\n\t// Confirmed live: with a delete here, the previous turn's ad stayed on\n\t// screen for the entire 4.7s until the real ad landed, which is exactly\n\t// the \"still shows the previous ad, no thinking text\" report this is\n\t// fixing.\n\t//\n\t// No `EXTENSION_STATUSBAR` counterpart here -- that status bar item is a\n\t// separate UI element `extension.ts` resets on its own (`showIdle`), not\n\t// `claudeCode.spinnerVerbs`.\n\tif (!terminalActive) {\n\t\twriteClaudeCodeSpinnerVerbsEverywhereInstalled(RESET_VERBS, RESET_VERBS);\n\t}\n\n\t// Deliberately does NOT re-assert the last cached ad before this fetch\n\t// (see `reapplyCachedSpinnerVerbs`'s doc comment for the tradeoff it was\n\t// built to close): doing so could flash a *stale* ad from a previous\n\t// turn/session -- possibly still on the logo fallback badge, or already\n\t// upgraded -- ahead of this turn's real one, landing as a visible\n\t// three-step flicker (stale ad -> reset -> fresh ad) that read worse\n\t// than the brief default-verb flash it was meant to prevent. Waiting for\n\t// the real fetch below is the more honest state to show, on request.\n\t// Scoped to `TERMINAL_PLACEMENTS` -- this call must never also touch\n\t// `EXTENSION_SPINNER`/`EXTENSION_STATUSBAR`. Those belong solely to\n\t// `extension.ts`'s idle timer (`EXTENSION_PLACEMENTS`); this hook running\n\t// with no explicit placements would fall back to `refreshAllPlacements`'s\n\t// default of all three, racing that timer's own writes to the same two\n\t// placements on every turn -- confirmed live: this produced a cache where\n\t// `extension_spinner` and `extension_statusbar` disagreed, each holding\n\t// whichever call's write landed last for that one placement.\n\tconst ads = await refreshAllPlacements(\n\t\tconfig,\n\t\tsessionId,\n\t\tTERMINAL_PLACEMENTS,\n\t);\n\n\t// The two branches below are NOT symmetric, on purpose:\n\t// - terminalActive: `ads` really was fetched for `TERMINAL_SPINNER`\n\t// (see the `TERMINAL_PLACEMENTS`-scoped call above), so `ads.has()`\n\t// is a meaningful check -- it's `false` only when api.kili genuinely\n\t// had nothing to serve (no active campaign), and skipping\n\t// `startPendingTurn` in that case is correct: nothing to settle later.\n\t// - !terminalActive (the IDE chat panel): `ads` was NEVER fetched for\n\t// `EXTENSION_SPINNER` at all -- that placement is deliberately outside\n\t// this hook's own `TERMINAL_PLACEMENTS`-scoped fetch (see the comment\n\t// above `refreshAllPlacements`). Gating this branch on `ads.has()`\n\t// too, as this code used to, meant the check was checking something\n\t// that was structurally never true regardless of whether an ad\n\t// existed -- `startPendingTurn` silently never fired for a single\n\t// panel turn, ever. Confirmed live: the panel spinner never advanced\n\t// off the extension's own 60s idle-timer cadence, no matter how many\n\t// messages were sent, because nothing ever wrote the pending-turn\n\t// record `extension.ts`'s per-turn fetch (`_checkForNewTurn`) polls\n\t// for. This branch is unconditional instead -- `extension.ts`'s own\n\t// fetch, triggered BY this pending-turn record existing, is what\n\t// actually resolves (or fails to resolve) an ad for this placement;\n\t// `settlePendingTurn` at `Stop` already no-ops safely if that fetch\n\t// never produced anything to settle.\n\tconst settledPlacements: string[] = terminalActive\n\t\t? ads.has(PLACEMENT.TERMINAL_SPINNER) ? [PLACEMENT.TERMINAL_SPINNER] : []\n\t\t: [PLACEMENT.EXTENSION_SPINNER];\n\tdebugLog(\"onUserPromptSubmit\", {\n\t\tterminalActive,\n\t\tsettledPlacements,\n\t});\n\n\tif (settledPlacements.length > 0) {\n\t\tstartPendingTurn({\n\t\t\tsessionId,\n\t\t\tplacementIds: settledPlacements,\n\t\t\tstartedAt: Date.now(),\n\t\t});\n\t}\n}\n\nfunction _readStdin(): Promise<string> {\n\treturn new Promise((resolve) => {\n\t\tlet data = \"\";\n\t\tprocess.stdin.setEncoding(\"utf8\");\n\t\tprocess.stdin.on(\"data\", (chunk) => {\n\t\t\tdata += chunk;\n\t\t});\n\t\tprocess.stdin.on(\"end\", () => resolve(data));\n\t\tprocess.stdin.on(\"error\", () => resolve(data));\n\t\t// Hooks always receive JSON on stdin, but guard against a hang if\n\t\t// Claude Code ever calls this without piping anything.\n\t\tsetTimeout(() => resolve(data), 2000);\n\t});\n}\n\nfunction _parsePayload(raw: string): TPayload {\n\ttry {\n\t\tconst json = JSON.parse(raw) as Record<string, unknown>;\n\t\treturn {\n\t\t\tsessionId:\n\t\t\t\ttypeof json.session_id === \"string\" ? json.session_id : undefined,\n\t\t\tuserInput:\n\t\t\t\ttypeof json.user_input === \"string\"\n\t\t\t\t\t? json.user_input\n\t\t\t\t\t: typeof json.prompt === \"string\"\n\t\t\t\t\t\t? json.prompt\n\t\t\t\t\t\t: undefined,\n\t\t};\n\t} catch {\n\t\treturn { sessionId: undefined, userInput: undefined };\n\t}\n}\n\nvoid main();\n"],"mappings":"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I;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAA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","names":["import_node_path","import_node_fs","import_node_path","value","CharacterCodes","ParseOptions","ScanError","SyntaxKind","parse","ParseErrorCode","parse","import_node_crypto","import_node_fs","import_node_os","import_node_path","import_node_fs","import_node_os","import_node_path","import_node_fs","import_node_path","_MAX_BYTES"]}
1
+ {"version":3,"sources":["../src/core/client.ts","../src/core/constants.ts","../src/core/debug.ts","../src/core/paths.ts","../src/core/errors.ts","../src/core/store.ts","../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js","../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/string-intern.js","../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/parser.js","../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/main.js","../src/core/cache.ts","../src/core/config.ts","../src/core/webviewPatch.ts","../src/core/copy.ts","../src/core/editorSettings.ts","../src/claude/settings.ts","../src/core/logoCache.ts","../src/core/refresh.ts","../src/hook.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { DEFAULT_API_URL, ERRORS } from \"./constants\";\nimport { debugLog } from \"./debug\";\nimport { KiliError } from \"./errors\";\nimport type { TAd, TAdsResult } from \"./types\";\n\nconst _defaultTimeoutMs = 5000;\n\nexport type TFetchAdsInput = {\n\tapiKey: string;\n\tapiUrl?: string;\n\t/** Every placement id fetched in one request/round trip -- api.kili's\n\t * `/ads` already accepts a `placements[]` array, and resolves one\n\t * relevant ad per request that it reuses across every placement passed\n\t * in. Requesting a caller's several surfaces together therefore both\n\t * costs one call instead of one per surface, and is what keeps every\n\t * surface showing the same single ad -- each placement still gets its\n\t * own trackId, so impressions/clicks are billed independently even\n\t * though the ad content is shared. */\n\tplacementIds: string[];\n\tsessionId: string;\n\tinstallId: string;\n};\n\n/**\n * Ports `pkg.api.cherry`'s `KiliApiClient.getAds` for a Node/VS Code caller\n * instead of an incoming HTTP request -- same wire contract\n * (`api.kili/src/transformers/ads.transformer.ts`).\n */\nexport class KiliClient {\n\t/** Keyed by placement id, value is every ad api.kili served for that\n\t * placement, in the order the server returned them -- how many that is\n\t * per call depends entirely on which `IAdServeStrategy` is configured\n\t * server-side (currently `RandomAdServeStrategy`, one ad; `ads.service.ts`\n\t * can also serve a whole shuffled candidate list under `AllAdServeStrategy`).\n\t * Either way this is grouped into an array per placement, never a single\n\t * value, so the client never has to know or care which strategy is live.\n\t * A placement api.kili had nothing to serve for (e.g. no active campaign)\n\t * simply has no entry -- callers should treat a missing key exactly like\n\t * \"no ad\", the same as an empty `ads[]` today. Grouping, not the old\n\t * `new Map(...)` overwrite: a `Map` built from `[placementId, ad]` pairs\n\t * silently keeps only the *last* entry for a repeated key, which is\n\t * exactly what used to throw away every ad but one under\n\t * `AllAdServeStrategy` -- confirmed live as the root cause of \"same ad\n\t * every time\". */\n\tpublic async fetchAds(input: TFetchAdsInput): Promise<Map<string, TAd[]>> {\n\t\tif (!input.apiKey) {\n\t\t\tthrow new KiliError(ERRORS.REQUIRED_API_KEY, 401);\n\t\t}\n\t\tconst baseUrl = input.apiUrl ?? DEFAULT_API_URL;\n\t\tconst result = await this._request(baseUrl, input);\n\t\t// KILI_DEBUG=1 only -- lets `favicon` (the ad's logo, see\n\t\t// `copy.ts`'s `spinnerVerbLink`) be confirmed present or absent in\n\t\t// the raw wire response, one hop before anything gets encoded into\n\t\t// a spinner verb or written to a webview.\n\t\tdebugLog(\n\t\t\t\"fetchAds\",\n\t\t\tresult.ads.map((ad) => ({\n\t\t\t\tplacementId: ad.placementId,\n\t\t\t\tadId: ad.adId,\n\t\t\t\thasFavicon: Boolean(ad.favicon),\n\t\t\t\tfavicon: ad.favicon,\n\t\t\t})),\n\t\t);\n\t\tconst grouped = new Map<string, TAd[]>();\n\t\tfor (const ad of result.ads) {\n\t\t\tconst list = grouped.get(ad.placementId);\n\t\t\tif (list) list.push(ad);\n\t\t\telse grouped.set(ad.placementId, [ad]);\n\t\t}\n\t\treturn grouped;\n\t}\n\n\tprivate async _request(\n\t\tbaseUrl: string,\n\t\tinput: TFetchAdsInput,\n\t): Promise<TAdsResult> {\n\t\tconst controller = new AbortController();\n\t\tconst timer = setTimeout(() => controller.abort(), _defaultTimeoutMs);\n\t\ttry {\n\t\t\tconst res = await fetch(`${baseUrl}/ads`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"content-type\": \"application/json\",\n\t\t\t\t\t\"x-kili-api-key\": input.apiKey,\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify(this._body(input)),\n\t\t\t\tsignal: controller.signal,\n\t\t\t});\n\t\t\tif (!res.ok) {\n\t\t\t\tthrow new KiliError(ERRORS.REQUEST_FAILED, res.status);\n\t\t\t}\n\t\t\treturn (await res.json()) as TAdsResult;\n\t\t} catch (error) {\n\t\t\tthrow this._toKiliError(error);\n\t\t} finally {\n\t\t\tclearTimeout(timer);\n\t\t}\n\t}\n\n\tprivate _body(input: TFetchAdsInput) {\n\t\treturn {\n\t\t\t// No `messages` field -- api.kili's ad selection (`RandomAdServeStrategy`\n\t\t\t// / `AllAdServeStrategy`, and the `IAdServeStrategy` interface itself)\n\t\t\t// never reads conversation content at all, so sending it here was pure\n\t\t\t// dead weight: payload size and server-side parsing for a field nothing\n\t\t\t// picks on. The wire schema still accepts it (optional, defaults to\n\t\t\t// `[]` server-side) for any other caller and for a future relevancy\n\t\t\t// strategy -- we just stopped being the one paying for it.\n\t\t\t// `placement` carries our own distinguishing value directly (see\n\t\t\t// PLACEMENT in constants.ts) rather than a shared generic slot type\n\t\t\t// -- that's the only field that lands in `ad_events`, so it has to be\n\t\t\t// the one that tells our four surfaces apart. `placementId` is still\n\t\t\t// a required wire field; sending the same value keeps the two in\n\t\t\t// sync without adding a second meaning to track.\n\t\t\tplacements: input.placementIds.map((placementId) => ({\n\t\t\t\tplacement: placementId,\n\t\t\t\tplacementId,\n\t\t\t})),\n\t\t\tkiliContext: {\n\t\t\t\tsessionId: this._sessionId(input.sessionId),\n\t\t\t\tuser: { userId: input.installId },\n\t\t\t\tdevice: {\n\t\t\t\t\tua: \"@kili-ai/ide\",\n\t\t\t\t\ttimezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n\t\t\t\t\tlocale: Intl.DateTimeFormat().resolvedOptions().locale,\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n\n\t/** api.kili requires a UUID; fall back to a fresh one when Claude's own\n\t * `session_id` doesn't parse as one. */\n\tprivate _sessionId(raw: string): string {\n\t\tconst uuidPattern =\n\t\t\t/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\t\treturn uuidPattern.test(raw) ? raw : randomUUID();\n\t}\n\n\tprivate _toKiliError(error: unknown): KiliError {\n\t\tif (error instanceof KiliError) return error;\n\t\tif (error instanceof Error && error.name === \"AbortError\") {\n\t\t\treturn new KiliError(ERRORS.TIMEOUT, 408);\n\t\t}\n\t\treturn new KiliError(ERRORS.NETWORK, 503);\n\t}\n}\n\n/**\n * Fire-and-forget beacon for `impUrl` / `clickUrl`. Never throws.\n *\n * Unlike a click (a real browser navigation straight to `clickUrl` -- if\n * `/track` rejects it, the browser itself shows an error page, so a broken\n * click is hard to miss), an impression's `/ack` call goes through this\n * function with nothing else ever inspecting the result. `fetch()` only\n * throws on network-level failures (DNS, connection refused, timeout) --\n * NOT on a 4xx/5xx response, so a server-side rejection (expired/malformed\n * JWT, `/ack` erroring) used to look identical to success from here: no\n * exception, `catch` never runs, caller marks the impression fired and moves\n * on, and the dashboard just never sees it. Logging `res.status` on every\n * call (only under `KILI_DEBUG=1`) is what makes that distinguishable from\n * an actually-successful beacon.\n */\nexport async function beacon(url: string | undefined): Promise<void> {\n\tif (!url) return;\n\ttry {\n\t\tconst res = await fetch(url, { method: \"GET\" });\n\t\tdebugLog(\"beacon\", { url, status: res.status, ok: res.ok });\n\t} catch (error) {\n\t\t// Billing beacons are best-effort from the client's side -- a dropped\n\t\t// beacon should never crash a spinner or a hook.\n\t\tdebugLog(\n\t\t\t\"beacon: threw\",\n\t\t\t{ url },\n\t\t\terror instanceof Error ? error.message : error,\n\t\t);\n\t}\n}\n","declare const __PACKAGE_VERSION__: string;\ndeclare const __DEFAULT_API_URL__: string;\ndeclare const __DEFAULT_WEB_URL__: string;\n\nexport const PACKAGE_VERSION =\n\ttypeof __PACKAGE_VERSION__ !== \"undefined\" ? __PACKAGE_VERSION__ : \"0.1.0\";\n\nexport const NPM_ORG = \"kili-ai\";\nexport const NPM_PACKAGE = \"ide\";\nexport const PACKAGE_NAME = `@${NPM_ORG}/${NPM_PACKAGE}`;\n\n/**\n * This literal fallback is always the PROD url, on every branch, including\n * `dev` -- never hand-edited per branch. A dev publish overrides it via\n * `KILI_API_URL`/`KILI_WEB_URL` (see `tsup.config.ts`), set only for the\n * duration of that one build/publish by `pkg.install.kili`'s\n * `scripts/publish-channel.cjs`, which also temporarily patches\n * `contributes.configuration.kili.apiUrl/webUrl`'s defaults in\n * `package.json` the same way and restores both files afterward. Keeping\n * dev/prod identity purely a publish-time concern, never a committed diff\n * between branches, is deliberate: `dev` and `master` are meant to be\n * merged into each other as normal feature work lands, and a real diff\n * here would silently carry one channel's URLs into the other on merge.\n */\nexport const DEFAULT_API_URL =\n\ttypeof __DEFAULT_API_URL__ !== \"undefined\"\n\t\t? __DEFAULT_API_URL__\n\t\t: \"https://api.trykili.ai\";\nexport const DEFAULT_WEB_URL =\n\ttypeof __DEFAULT_WEB_URL__ !== \"undefined\"\n\t\t? __DEFAULT_WEB_URL__\n\t\t: \"https://app.trykili.ai\";\nexport const CLI_AUTH_PATH = \"/cli-auth\";\nexport const AUTH_TIMEOUT_MS = 5 * 60 * 1000;\n\n/**\n * Distinct placement ids per surface, self-descriptive on their own in\n * `ad_events` -- no cross-referencing code to know a\n * \"claude_code_extension_spinner\" row came from this package's editor\n * sidebar, not the terminal. Named `<app>_<surface>` throughout: `terminal`\n * for the CLI, `extension` for the VS Code/Cursor sidebar; `spinner` (text,\n * impression-only, can't be clicked) vs `statusline`/`statusbar` (rendered\n * by us, clickable). Each gets served in the same `/ads` call as its\n * sibling surface but is still a fully separate placement -- separately\n * priced, separately reported, never sharing one fetched ad relabeled two\n * ways.\n */\nexport const PLACEMENT = {\n\tTERMINAL_SPINNER: \"claude_code_terminal_spinner\",\n\tTERMINAL_STATUSLINE: \"claude_code_terminal_statusline\",\n\tEXTENSION_SPINNER: \"claude_code_extension_spinner\",\n\tEXTENSION_STATUSBAR: \"claude_code_extension_statusbar\",\n} as const;\n\n/**\n * How long an ad must be continuously visible before we consider it a real\n * impression and fire `impUrl`. Was 10s (a standard \"qualifying view\"\n * convention), lowered to 3s, then to 0 on request --\n * \"shown is enough, no time limit\". At 0, `markRenderedAndClaimImpression`\n * still needs a second render call to fire (its first call only records\n * `firstSeenAt`), so it's \"next render tick\" rather than truly instant --\n * but for `settlePendingTurn`, 0 means every turn that completes at all\n * qualifies, however short. This is a real tradeoff, not a free tuning\n * knob: it removes any distinction between an ad that was actually seen and\n * one that flickered past for a fraction of a second before the next turn\n * replaced it.\n */\nexport const DWELL_THRESHOLD_MS = 0;\n\nexport const ERRORS = {\n\tREQUIRED_API_KEY: 'Kili API key is required. Run \"Kili: Sign In\".',\n\tREQUEST_FAILED: \"Kili request failed.\",\n\tTIMEOUT: \"Kili request timed out.\",\n\tNETWORK: \"Kili network error.\",\n};\n","import { appendFileSync, mkdirSync, renameSync, statSync } from \"node:fs\";\nimport { basename, dirname } from \"node:path\";\nimport { debugLogPath } from \"./paths\";\n\n/**\n * Logs to `~/.kili/debug.log` ALWAYS, and additionally to stderr when\n * `KILI_DEBUG=1`.\n *\n * The file is the point. Two of the three processes in this package are\n * one-shot children spawned by Claude Code -- `hook.ts` (per turn) and\n * `statusline.ts` (roughly every 300ms) -- and neither one's stderr is\n * displayed anywhere a user or a developer can see it. For most of this\n * package's life that meant the per-turn ad path, the single most\n * bug-prone thing here, produced no observable trace at all: diagnosing it\n * came down to reading `~/.kili/*.json` mtimes and guessing at ordering\n * between three processes. A durable, timestamped, process-tagged file\n * removes the guessing.\n *\n * Never stdout -- `hook.ts`'s stdout is read by Claude Code and, for\n * `UserPromptSubmit`, injected into the model's own context, so anything\n * printed there must be exactly what that hook contract expects and nothing\n * else. Never throws, either: logging must never be able to break the ad\n * path it exists to observe.\n */\n\n/** Rotated (not truncated) at this size so the previous window survives one\n * more run -- a bug reproduced once tends to get looked at after the fact,\n * and dropping the only copy of that evidence to save a few hundred KB is a\n * bad trade. */\nconst _MAX_BYTES = 256_000;\n\n/** Which of the three processes wrote a line. `hook`/`statusline` are the\n * ones with nowhere else to log; `extension` runs in the extension host and\n * also has an Output channel, but shares this file so one timeline covers\n * all three. */\nfunction _processTag(): string {\n\tconst entry = process.argv[1];\n\tif (!entry) return \"?\";\n\tconst name = basename(entry).replace(/\\.[cm]?js$/, \"\");\n\treturn name || \"?\";\n}\n\nfunction _rotateIfLarge(path: string): void {\n\ttry {\n\t\tif (statSync(path).size < _MAX_BYTES) return;\n\t\trenameSync(path, `${path}.1`);\n\t} catch {\n\t\t/* no file yet, or rotation raced another process -- either is fine */\n\t}\n}\n\nfunction _format(args: unknown[]): string {\n\treturn args\n\t\t.map((arg) => {\n\t\t\tif (typeof arg === \"string\") return arg;\n\t\t\tif (arg instanceof Error) return `${arg.name}: ${arg.message}`;\n\t\t\ttry {\n\t\t\t\treturn JSON.stringify(arg);\n\t\t\t} catch {\n\t\t\t\treturn String(arg);\n\t\t\t}\n\t\t})\n\t\t.join(\" \");\n}\n\nexport function debugLog(...args: unknown[]): void {\n\tif (process.env.KILI_DEBUG === \"1\") {\n\t\tconsole.error(\"[kili]\", ...args);\n\t}\n\ttry {\n\t\tconst path = debugLogPath();\n\t\tmkdirSync(dirname(path), { recursive: true });\n\t\t_rotateIfLarge(path);\n\t\tconst line = `${new Date().toISOString()} [${_processTag()}] ${_format(args)}\\n`;\n\t\tappendFileSync(path, line, \"utf8\");\n\t} catch {\n\t\t/* logging must never break the caller -- see this file's doc comment */\n\t}\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\n/** Kili's own state directory -- separate from `~/.claude`, since we never\n * want a bug in our code to risk corrupting Claude's own state. */\nexport function kiliHome(): string {\n\treturn join(homedir(), \".kili\");\n}\n\nexport function adCachePath(): string {\n\treturn join(kiliHome(), \"ad-cache.json\");\n}\n\n/** Data-URI cache for logo images (see `logoCache.ts`), keyed by their\n * original remote URL. Separate file from `ad-cache.json` because it\n * outlives any single ad -- the same brand's logo URL recurs across many\n * different ads/campaigns, so the fetch-and-encode cost should only ever be\n * paid once per URL, not once per ad. */\nexport function logoCachePath(): string {\n\treturn join(kiliHome(), \"logo-cache.json\");\n}\n\nexport function pendingTurnPath(): string {\n\treturn join(kiliHome(), \"pending-turn.json\");\n}\n\n/** Written by `statusline.ts` on every invocation -- the only reliable\n * signal that a real terminal is actually rendering `statusLine` right now.\n * The IDE chat panel never runs this script (it reads `claudeCode.spinnerVerbs`\n * straight from its own webview, a completely separate mechanism), so a\n * fresh heartbeat here means a real terminal, not the chat panel, is what's\n * currently in front of the user. See `isTerminalActive` in `cache.ts`. */\nexport function terminalHeartbeatPath(): string {\n\treturn join(kiliHome(), \"terminal-heartbeat.json\");\n}\n\nexport function runtimeConfigPath(): string {\n\treturn join(kiliHome(), \"config.json\");\n}\n\n/** Where `debug.ts` writes its always-on log. One file shared by all three\n * processes (`extension`, `hook`, `statusline`) on purpose -- the bugs worth\n * diagnosing here are ordering bugs *between* them, which a per-process file\n * would split apart. */\nexport function debugLogPath(): string {\n\treturn join(kiliHome(), \"debug.log\");\n}\n\nexport function settingsBackupPath(): string {\n\treturn join(kiliHome(), \"settings.backup.json\");\n}\n\nexport function claudeSettingsPath(): string {\n\treturn join(homedir(), \".claude\", \"settings.json\");\n}\n","export class KiliError extends Error {\n\tpublic readonly statusCode: number;\n\n\tconstructor(message: string, statusCode: number) {\n\t\tsuper(message);\n\t\tthis.name = \"KiliError\";\n\t\tthis.statusCode = statusCode;\n\t}\n}\n","import {\n\texistsSync,\n\tmkdirSync,\n\treadFileSync,\n\trenameSync,\n\tunlinkSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport {\n\ttype ParseError,\n\tparse as parseJsonc,\n\tprintParseErrorCode,\n} from \"jsonc-parser\";\n\n/**\n * Atomic JSON read/write for the cache files three separate OS processes\n * touch concurrently: the extension host's refresh timer, `statusline.ts`\n * (spawned fresh on every render by Claude Code), and `hook.ts` (spawned\n * fresh on every turn). Writing to a temp file and renaming over the target\n * means a reader never observes a half-written file.\n */\n\nexport function readJson<T>(path: string, fallback: T): T {\n\tif (!existsSync(path)) return fallback;\n\ttry {\n\t\treturn JSON.parse(readFileSync(path, \"utf8\")) as T;\n\t} catch {\n\t\treturn fallback;\n\t}\n}\n\n/**\n * Thrown by `readJsonOwnedByUser` when a file exists but can't be parsed --\n * never caught silently by that function itself, unlike `readJson`.\n */\nexport class SettingsParseError extends Error {}\n\n/**\n * For files we don't own -- the user's editor `settings.json`, or\n * `~/.claude/settings.json` -- never `readJson`. That function treats \"I\n * couldn't parse this\" the same as \"the file doesn't exist\", which is\n * correct for our own cache files (nobody else ever hand-edits\n * `~/.kili/ad-cache.json`) but is real data loss here: VS Code's own\n * settings.json commonly has `//` comments and trailing commas (JSONC,\n * which the editor accepts fine but `JSON.parse` doesn't), so a perfectly\n * normal settings.json would silently look \"empty\" to a merge-write --\n * which then writes back *only* our own key, discarding the user's theme,\n * activity bar layout, everything else in the file. Confirmed: this\n * happened for real.\n *\n * Parsed with `jsonc-parser` (the same library VS Code's own settings UI\n * uses), NOT `JSON.parse` -- a bare `JSON.parse` used to reject comments and\n * trailing commas outright, which meant an ordinary, valid settings.json\n * (comments are completely normal there) permanently threw here and blocked\n * every write forever, e.g. `kili.apiKey` never landing on sign-in.\n * Confirmed live: this happened for real too, on a ordinary hand-commented\n * settings.json, not a corrupted one. `allowTrailingComma: true` because\n * VS Code's editor accepts those on save; comments need no explicit opt-in,\n * `parse()` always tolerates them.\n *\n * Missing file -> `fallback` (nothing to lose, safe to start fresh).\n * Existing but genuinely unparseable file (real syntax errors beyond\n * JSONC's comments/trailing commas) -> throws, so the caller aborts the\n * write instead of clobbering it. Callers must catch this and skip/warn,\n * not crash outright -- see `claude/settings.ts` and `editorSettings.ts`.\n */\nexport function readJsonOwnedByUser<T>(path: string, fallback: T): T {\n\tif (!existsSync(path)) return fallback;\n\tconst text = readFileSync(path, \"utf8\");\n\tconst errors: ParseError[] = [];\n\tconst parsed = parseJsonc(text, errors, { allowTrailingComma: true });\n\tif (errors.length > 0) {\n\t\tconst first = errors[0];\n\t\tthrow new SettingsParseError(\n\t\t\t`${path} exists but could not be parsed as JSON, even allowing for ` +\n\t\t\t\t`JSONC comments/trailing commas -- refusing to overwrite it. ` +\n\t\t\t\t`(${printParseErrorCode(first.error)} at offset ${first.offset})`,\n\t\t);\n\t}\n\treturn parsed as T;\n}\n\nexport function writeJsonAtomic(path: string, value: unknown): void {\n\tmkdirSync(dirname(path), { recursive: true });\n\tconst tmp = `${path}.tmp-${process.pid}-${Date.now()}`;\n\twriteFileSync(tmp, JSON.stringify(value), \"utf8\");\n\ttry {\n\t\trenameSync(tmp, path);\n\t} catch {\n\t\t// Cross-device rename can fail on some Windows setups -- fall back to\n\t\t// a direct write, which is not atomic but still correct absent a\n\t\t// concurrent writer mid-read.\n\t\twriteFileSync(path, JSON.stringify(value), \"utf8\");\n\t\ttry {\n\t\t\tunlinkSync(tmp);\n\t\t} catch {\n\t\t\t/* best effort cleanup */\n\t\t}\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n'use strict';\n/**\n * Creates a JSON scanner on the given text.\n * If ignoreTrivia is set, whitespaces or comments are ignored.\n */\nexport function createScanner(text, ignoreTrivia = false) {\n const len = text.length;\n let pos = 0, value = '', tokenOffset = 0, token = 16 /* SyntaxKind.Unknown */, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0 /* ScanError.None */;\n function scanHexDigits(count, exact) {\n let digits = 0;\n let value = 0;\n while (digits < count || !exact) {\n let ch = text.charCodeAt(pos);\n if (ch >= 48 /* CharacterCodes._0 */ && ch <= 57 /* CharacterCodes._9 */) {\n value = value * 16 + ch - 48 /* CharacterCodes._0 */;\n }\n else if (ch >= 65 /* CharacterCodes.A */ && ch <= 70 /* CharacterCodes.F */) {\n value = value * 16 + ch - 65 /* CharacterCodes.A */ + 10;\n }\n else if (ch >= 97 /* CharacterCodes.a */ && ch <= 102 /* CharacterCodes.f */) {\n value = value * 16 + ch - 97 /* CharacterCodes.a */ + 10;\n }\n else {\n break;\n }\n pos++;\n digits++;\n }\n if (digits < count) {\n value = -1;\n }\n return value;\n }\n function setPosition(newPosition) {\n pos = newPosition;\n value = '';\n tokenOffset = 0;\n token = 16 /* SyntaxKind.Unknown */;\n scanError = 0 /* ScanError.None */;\n }\n function scanNumber() {\n let start = pos;\n if (text.charCodeAt(pos) === 48 /* CharacterCodes._0 */) {\n pos++;\n }\n else {\n pos++;\n while (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n }\n }\n if (pos < text.length && text.charCodeAt(pos) === 46 /* CharacterCodes.dot */) {\n pos++;\n if (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n while (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n }\n }\n else {\n scanError = 3 /* ScanError.UnexpectedEndOfNumber */;\n return text.substring(start, pos);\n }\n }\n let end = pos;\n if (pos < text.length && (text.charCodeAt(pos) === 69 /* CharacterCodes.E */ || text.charCodeAt(pos) === 101 /* CharacterCodes.e */)) {\n pos++;\n if (pos < text.length && text.charCodeAt(pos) === 43 /* CharacterCodes.plus */ || text.charCodeAt(pos) === 45 /* CharacterCodes.minus */) {\n pos++;\n }\n if (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n while (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n }\n end = pos;\n }\n else {\n scanError = 3 /* ScanError.UnexpectedEndOfNumber */;\n }\n }\n return text.substring(start, end);\n }\n function scanString() {\n let result = '', start = pos;\n while (true) {\n if (pos >= len) {\n result += text.substring(start, pos);\n scanError = 2 /* ScanError.UnexpectedEndOfString */;\n break;\n }\n const ch = text.charCodeAt(pos);\n if (ch === 34 /* CharacterCodes.doubleQuote */) {\n result += text.substring(start, pos);\n pos++;\n break;\n }\n if (ch === 92 /* CharacterCodes.backslash */) {\n result += text.substring(start, pos);\n pos++;\n if (pos >= len) {\n scanError = 2 /* ScanError.UnexpectedEndOfString */;\n break;\n }\n const ch2 = text.charCodeAt(pos++);\n switch (ch2) {\n case 34 /* CharacterCodes.doubleQuote */:\n result += '\\\"';\n break;\n case 92 /* CharacterCodes.backslash */:\n result += '\\\\';\n break;\n case 47 /* CharacterCodes.slash */:\n result += '/';\n break;\n case 98 /* CharacterCodes.b */:\n result += '\\b';\n break;\n case 102 /* CharacterCodes.f */:\n result += '\\f';\n break;\n case 110 /* CharacterCodes.n */:\n result += '\\n';\n break;\n case 114 /* CharacterCodes.r */:\n result += '\\r';\n break;\n case 116 /* CharacterCodes.t */:\n result += '\\t';\n break;\n case 117 /* CharacterCodes.u */:\n const ch3 = scanHexDigits(4, true);\n if (ch3 >= 0) {\n result += String.fromCharCode(ch3);\n }\n else {\n scanError = 4 /* ScanError.InvalidUnicode */;\n }\n break;\n default:\n scanError = 5 /* ScanError.InvalidEscapeCharacter */;\n }\n start = pos;\n continue;\n }\n if (ch >= 0 && ch <= 0x1f) {\n if (isLineBreak(ch)) {\n result += text.substring(start, pos);\n scanError = 2 /* ScanError.UnexpectedEndOfString */;\n break;\n }\n else {\n scanError = 6 /* ScanError.InvalidCharacter */;\n // mark as error but continue with string\n }\n }\n pos++;\n }\n return result;\n }\n function scanNext() {\n value = '';\n scanError = 0 /* ScanError.None */;\n tokenOffset = pos;\n lineStartOffset = lineNumber;\n prevTokenLineStartOffset = tokenLineStartOffset;\n if (pos >= len) {\n // at the end\n tokenOffset = len;\n return token = 17 /* SyntaxKind.EOF */;\n }\n let code = text.charCodeAt(pos);\n // trivia: whitespace\n if (isWhiteSpace(code)) {\n do {\n pos++;\n value += String.fromCharCode(code);\n code = text.charCodeAt(pos);\n } while (isWhiteSpace(code));\n return token = 15 /* SyntaxKind.Trivia */;\n }\n // trivia: newlines\n if (isLineBreak(code)) {\n pos++;\n value += String.fromCharCode(code);\n if (code === 13 /* CharacterCodes.carriageReturn */ && text.charCodeAt(pos) === 10 /* CharacterCodes.lineFeed */) {\n pos++;\n value += '\\n';\n }\n lineNumber++;\n tokenLineStartOffset = pos;\n return token = 14 /* SyntaxKind.LineBreakTrivia */;\n }\n switch (code) {\n // tokens: []{}:,\n case 123 /* CharacterCodes.openBrace */:\n pos++;\n return token = 1 /* SyntaxKind.OpenBraceToken */;\n case 125 /* CharacterCodes.closeBrace */:\n pos++;\n return token = 2 /* SyntaxKind.CloseBraceToken */;\n case 91 /* CharacterCodes.openBracket */:\n pos++;\n return token = 3 /* SyntaxKind.OpenBracketToken */;\n case 93 /* CharacterCodes.closeBracket */:\n pos++;\n return token = 4 /* SyntaxKind.CloseBracketToken */;\n case 58 /* CharacterCodes.colon */:\n pos++;\n return token = 6 /* SyntaxKind.ColonToken */;\n case 44 /* CharacterCodes.comma */:\n pos++;\n return token = 5 /* SyntaxKind.CommaToken */;\n // strings\n case 34 /* CharacterCodes.doubleQuote */:\n pos++;\n value = scanString();\n return token = 10 /* SyntaxKind.StringLiteral */;\n // comments\n case 47 /* CharacterCodes.slash */:\n const start = pos - 1;\n // Single-line comment\n if (text.charCodeAt(pos + 1) === 47 /* CharacterCodes.slash */) {\n pos += 2;\n while (pos < len) {\n if (isLineBreak(text.charCodeAt(pos))) {\n break;\n }\n pos++;\n }\n value = text.substring(start, pos);\n return token = 12 /* SyntaxKind.LineCommentTrivia */;\n }\n // Multi-line comment\n if (text.charCodeAt(pos + 1) === 42 /* CharacterCodes.asterisk */) {\n pos += 2;\n const safeLength = len - 1; // For lookahead.\n let commentClosed = false;\n while (pos < safeLength) {\n const ch = text.charCodeAt(pos);\n if (ch === 42 /* CharacterCodes.asterisk */ && text.charCodeAt(pos + 1) === 47 /* CharacterCodes.slash */) {\n pos += 2;\n commentClosed = true;\n break;\n }\n pos++;\n if (isLineBreak(ch)) {\n if (ch === 13 /* CharacterCodes.carriageReturn */ && text.charCodeAt(pos) === 10 /* CharacterCodes.lineFeed */) {\n pos++;\n }\n lineNumber++;\n tokenLineStartOffset = pos;\n }\n }\n if (!commentClosed) {\n pos++;\n scanError = 1 /* ScanError.UnexpectedEndOfComment */;\n }\n value = text.substring(start, pos);\n return token = 13 /* SyntaxKind.BlockCommentTrivia */;\n }\n // just a single slash\n value += String.fromCharCode(code);\n pos++;\n return token = 16 /* SyntaxKind.Unknown */;\n // numbers\n case 45 /* CharacterCodes.minus */:\n value += String.fromCharCode(code);\n pos++;\n if (pos === len || !isDigit(text.charCodeAt(pos))) {\n return token = 16 /* SyntaxKind.Unknown */;\n }\n // found a minus, followed by a number so\n // we fall through to proceed with scanning\n // numbers\n case 48 /* CharacterCodes._0 */:\n case 49 /* CharacterCodes._1 */:\n case 50 /* CharacterCodes._2 */:\n case 51 /* CharacterCodes._3 */:\n case 52 /* CharacterCodes._4 */:\n case 53 /* CharacterCodes._5 */:\n case 54 /* CharacterCodes._6 */:\n case 55 /* CharacterCodes._7 */:\n case 56 /* CharacterCodes._8 */:\n case 57 /* CharacterCodes._9 */:\n value += scanNumber();\n return token = 11 /* SyntaxKind.NumericLiteral */;\n // literals and unknown symbols\n default:\n // is a literal? Read the full word.\n while (pos < len && isUnknownContentCharacter(code)) {\n pos++;\n code = text.charCodeAt(pos);\n }\n if (tokenOffset !== pos) {\n value = text.substring(tokenOffset, pos);\n // keywords: true, false, null\n switch (value) {\n case 'true': return token = 8 /* SyntaxKind.TrueKeyword */;\n case 'false': return token = 9 /* SyntaxKind.FalseKeyword */;\n case 'null': return token = 7 /* SyntaxKind.NullKeyword */;\n }\n return token = 16 /* SyntaxKind.Unknown */;\n }\n // some\n value += String.fromCharCode(code);\n pos++;\n return token = 16 /* SyntaxKind.Unknown */;\n }\n }\n function isUnknownContentCharacter(code) {\n if (isWhiteSpace(code) || isLineBreak(code)) {\n return false;\n }\n switch (code) {\n case 125 /* CharacterCodes.closeBrace */:\n case 93 /* CharacterCodes.closeBracket */:\n case 123 /* CharacterCodes.openBrace */:\n case 91 /* CharacterCodes.openBracket */:\n case 34 /* CharacterCodes.doubleQuote */:\n case 58 /* CharacterCodes.colon */:\n case 44 /* CharacterCodes.comma */:\n case 47 /* CharacterCodes.slash */:\n return false;\n }\n return true;\n }\n function scanNextNonTrivia() {\n let result;\n do {\n result = scanNext();\n } while (result >= 12 /* SyntaxKind.LineCommentTrivia */ && result <= 15 /* SyntaxKind.Trivia */);\n return result;\n }\n return {\n setPosition: setPosition,\n getPosition: () => pos,\n scan: ignoreTrivia ? scanNextNonTrivia : scanNext,\n getToken: () => token,\n getTokenValue: () => value,\n getTokenOffset: () => tokenOffset,\n getTokenLength: () => pos - tokenOffset,\n getTokenStartLine: () => lineStartOffset,\n getTokenStartCharacter: () => tokenOffset - prevTokenLineStartOffset,\n getTokenError: () => scanError,\n };\n}\nfunction isWhiteSpace(ch) {\n return ch === 32 /* CharacterCodes.space */ || ch === 9 /* CharacterCodes.tab */;\n}\nfunction isLineBreak(ch) {\n return ch === 10 /* CharacterCodes.lineFeed */ || ch === 13 /* CharacterCodes.carriageReturn */;\n}\nfunction isDigit(ch) {\n return ch >= 48 /* CharacterCodes._0 */ && ch <= 57 /* CharacterCodes._9 */;\n}\nvar CharacterCodes;\n(function (CharacterCodes) {\n CharacterCodes[CharacterCodes[\"lineFeed\"] = 10] = \"lineFeed\";\n CharacterCodes[CharacterCodes[\"carriageReturn\"] = 13] = \"carriageReturn\";\n CharacterCodes[CharacterCodes[\"space\"] = 32] = \"space\";\n CharacterCodes[CharacterCodes[\"_0\"] = 48] = \"_0\";\n CharacterCodes[CharacterCodes[\"_1\"] = 49] = \"_1\";\n CharacterCodes[CharacterCodes[\"_2\"] = 50] = \"_2\";\n CharacterCodes[CharacterCodes[\"_3\"] = 51] = \"_3\";\n CharacterCodes[CharacterCodes[\"_4\"] = 52] = \"_4\";\n CharacterCodes[CharacterCodes[\"_5\"] = 53] = \"_5\";\n CharacterCodes[CharacterCodes[\"_6\"] = 54] = \"_6\";\n CharacterCodes[CharacterCodes[\"_7\"] = 55] = \"_7\";\n CharacterCodes[CharacterCodes[\"_8\"] = 56] = \"_8\";\n CharacterCodes[CharacterCodes[\"_9\"] = 57] = \"_9\";\n CharacterCodes[CharacterCodes[\"a\"] = 97] = \"a\";\n CharacterCodes[CharacterCodes[\"b\"] = 98] = \"b\";\n CharacterCodes[CharacterCodes[\"c\"] = 99] = \"c\";\n CharacterCodes[CharacterCodes[\"d\"] = 100] = \"d\";\n CharacterCodes[CharacterCodes[\"e\"] = 101] = \"e\";\n CharacterCodes[CharacterCodes[\"f\"] = 102] = \"f\";\n CharacterCodes[CharacterCodes[\"g\"] = 103] = \"g\";\n CharacterCodes[CharacterCodes[\"h\"] = 104] = \"h\";\n CharacterCodes[CharacterCodes[\"i\"] = 105] = \"i\";\n CharacterCodes[CharacterCodes[\"j\"] = 106] = \"j\";\n CharacterCodes[CharacterCodes[\"k\"] = 107] = \"k\";\n CharacterCodes[CharacterCodes[\"l\"] = 108] = \"l\";\n CharacterCodes[CharacterCodes[\"m\"] = 109] = \"m\";\n CharacterCodes[CharacterCodes[\"n\"] = 110] = \"n\";\n CharacterCodes[CharacterCodes[\"o\"] = 111] = \"o\";\n CharacterCodes[CharacterCodes[\"p\"] = 112] = \"p\";\n CharacterCodes[CharacterCodes[\"q\"] = 113] = \"q\";\n CharacterCodes[CharacterCodes[\"r\"] = 114] = \"r\";\n CharacterCodes[CharacterCodes[\"s\"] = 115] = \"s\";\n CharacterCodes[CharacterCodes[\"t\"] = 116] = \"t\";\n CharacterCodes[CharacterCodes[\"u\"] = 117] = \"u\";\n CharacterCodes[CharacterCodes[\"v\"] = 118] = \"v\";\n CharacterCodes[CharacterCodes[\"w\"] = 119] = \"w\";\n CharacterCodes[CharacterCodes[\"x\"] = 120] = \"x\";\n CharacterCodes[CharacterCodes[\"y\"] = 121] = \"y\";\n CharacterCodes[CharacterCodes[\"z\"] = 122] = \"z\";\n CharacterCodes[CharacterCodes[\"A\"] = 65] = \"A\";\n CharacterCodes[CharacterCodes[\"B\"] = 66] = \"B\";\n CharacterCodes[CharacterCodes[\"C\"] = 67] = \"C\";\n CharacterCodes[CharacterCodes[\"D\"] = 68] = \"D\";\n CharacterCodes[CharacterCodes[\"E\"] = 69] = \"E\";\n CharacterCodes[CharacterCodes[\"F\"] = 70] = \"F\";\n CharacterCodes[CharacterCodes[\"G\"] = 71] = \"G\";\n CharacterCodes[CharacterCodes[\"H\"] = 72] = \"H\";\n CharacterCodes[CharacterCodes[\"I\"] = 73] = \"I\";\n CharacterCodes[CharacterCodes[\"J\"] = 74] = \"J\";\n CharacterCodes[CharacterCodes[\"K\"] = 75] = \"K\";\n CharacterCodes[CharacterCodes[\"L\"] = 76] = \"L\";\n CharacterCodes[CharacterCodes[\"M\"] = 77] = \"M\";\n CharacterCodes[CharacterCodes[\"N\"] = 78] = \"N\";\n CharacterCodes[CharacterCodes[\"O\"] = 79] = \"O\";\n CharacterCodes[CharacterCodes[\"P\"] = 80] = \"P\";\n CharacterCodes[CharacterCodes[\"Q\"] = 81] = \"Q\";\n CharacterCodes[CharacterCodes[\"R\"] = 82] = \"R\";\n CharacterCodes[CharacterCodes[\"S\"] = 83] = \"S\";\n CharacterCodes[CharacterCodes[\"T\"] = 84] = \"T\";\n CharacterCodes[CharacterCodes[\"U\"] = 85] = \"U\";\n CharacterCodes[CharacterCodes[\"V\"] = 86] = \"V\";\n CharacterCodes[CharacterCodes[\"W\"] = 87] = \"W\";\n CharacterCodes[CharacterCodes[\"X\"] = 88] = \"X\";\n CharacterCodes[CharacterCodes[\"Y\"] = 89] = \"Y\";\n CharacterCodes[CharacterCodes[\"Z\"] = 90] = \"Z\";\n CharacterCodes[CharacterCodes[\"asterisk\"] = 42] = \"asterisk\";\n CharacterCodes[CharacterCodes[\"backslash\"] = 92] = \"backslash\";\n CharacterCodes[CharacterCodes[\"closeBrace\"] = 125] = \"closeBrace\";\n CharacterCodes[CharacterCodes[\"closeBracket\"] = 93] = \"closeBracket\";\n CharacterCodes[CharacterCodes[\"colon\"] = 58] = \"colon\";\n CharacterCodes[CharacterCodes[\"comma\"] = 44] = \"comma\";\n CharacterCodes[CharacterCodes[\"dot\"] = 46] = \"dot\";\n CharacterCodes[CharacterCodes[\"doubleQuote\"] = 34] = \"doubleQuote\";\n CharacterCodes[CharacterCodes[\"minus\"] = 45] = \"minus\";\n CharacterCodes[CharacterCodes[\"openBrace\"] = 123] = \"openBrace\";\n CharacterCodes[CharacterCodes[\"openBracket\"] = 91] = \"openBracket\";\n CharacterCodes[CharacterCodes[\"plus\"] = 43] = \"plus\";\n CharacterCodes[CharacterCodes[\"slash\"] = 47] = \"slash\";\n CharacterCodes[CharacterCodes[\"formFeed\"] = 12] = \"formFeed\";\n CharacterCodes[CharacterCodes[\"tab\"] = 9] = \"tab\";\n})(CharacterCodes || (CharacterCodes = {}));\n","export const cachedSpaces = new Array(20).fill(0).map((_, index) => {\n return ' '.repeat(index);\n});\nconst maxCachedValues = 200;\nexport const cachedBreakLinesWithSpaces = {\n ' ': {\n '\\n': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\n' + ' '.repeat(index);\n }),\n '\\r': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\r' + ' '.repeat(index);\n }),\n '\\r\\n': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\r\\n' + ' '.repeat(index);\n }),\n },\n '\\t': {\n '\\n': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\n' + '\\t'.repeat(index);\n }),\n '\\r': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\r' + '\\t'.repeat(index);\n }),\n '\\r\\n': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\r\\n' + '\\t'.repeat(index);\n }),\n }\n};\nexport const supportedEols = ['\\n', '\\r', '\\r\\n'];\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n'use strict';\nimport { createScanner } from './scanner';\nvar ParseOptions;\n(function (ParseOptions) {\n ParseOptions.DEFAULT = {\n allowTrailingComma: false\n };\n})(ParseOptions || (ParseOptions = {}));\n/**\n * For a given offset, evaluate the location in the JSON document. Each segment in the location path is either a property name or an array index.\n */\nexport function getLocation(text, position) {\n const segments = []; // strings or numbers\n const earlyReturnException = new Object();\n let previousNode = undefined;\n const previousNodeInst = {\n value: {},\n offset: 0,\n length: 0,\n type: 'object',\n parent: undefined\n };\n let isAtPropertyKey = false;\n function setPreviousNode(value, offset, length, type) {\n previousNodeInst.value = value;\n previousNodeInst.offset = offset;\n previousNodeInst.length = length;\n previousNodeInst.type = type;\n previousNodeInst.colonOffset = undefined;\n previousNode = previousNodeInst;\n }\n try {\n visit(text, {\n onObjectBegin: (offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n previousNode = undefined;\n isAtPropertyKey = position > offset;\n segments.push(''); // push a placeholder (will be replaced)\n },\n onObjectProperty: (name, offset, length) => {\n if (position < offset) {\n throw earlyReturnException;\n }\n setPreviousNode(name, offset, length, 'property');\n segments[segments.length - 1] = name;\n if (position <= offset + length) {\n throw earlyReturnException;\n }\n },\n onObjectEnd: (offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n previousNode = undefined;\n segments.pop();\n },\n onArrayBegin: (offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n previousNode = undefined;\n segments.push(0);\n },\n onArrayEnd: (offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n previousNode = undefined;\n segments.pop();\n },\n onLiteralValue: (value, offset, length) => {\n if (position < offset) {\n throw earlyReturnException;\n }\n setPreviousNode(value, offset, length, getNodeType(value));\n if (position <= offset + length) {\n throw earlyReturnException;\n }\n },\n onSeparator: (sep, offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n if (sep === ':' && previousNode && previousNode.type === 'property') {\n previousNode.colonOffset = offset;\n isAtPropertyKey = false;\n previousNode = undefined;\n }\n else if (sep === ',') {\n const last = segments[segments.length - 1];\n if (typeof last === 'number') {\n segments[segments.length - 1] = last + 1;\n }\n else {\n isAtPropertyKey = true;\n segments[segments.length - 1] = '';\n }\n previousNode = undefined;\n }\n }\n });\n }\n catch (e) {\n if (e !== earlyReturnException) {\n throw e;\n }\n }\n return {\n path: segments,\n previousNode,\n isAtPropertyKey,\n matches: (pattern) => {\n let k = 0;\n for (let i = 0; k < pattern.length && i < segments.length; i++) {\n if (pattern[k] === segments[i] || pattern[k] === '*') {\n k++;\n }\n else if (pattern[k] !== '**') {\n return false;\n }\n }\n return k === pattern.length;\n }\n };\n}\n/**\n * Parses the given text and returns the object the JSON content represents. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.\n * Therefore always check the errors list to find out if the input was valid.\n */\nexport function parse(text, errors = [], options = ParseOptions.DEFAULT) {\n let currentProperty = null;\n let currentParent = [];\n const previousParents = [];\n function onValue(value) {\n if (Array.isArray(currentParent)) {\n currentParent.push(value);\n }\n else if (currentProperty !== null) {\n currentParent[currentProperty] = value;\n }\n }\n const visitor = {\n onObjectBegin: () => {\n const object = {};\n onValue(object);\n previousParents.push(currentParent);\n currentParent = object;\n currentProperty = null;\n },\n onObjectProperty: (name) => {\n currentProperty = name;\n },\n onObjectEnd: () => {\n currentParent = previousParents.pop();\n },\n onArrayBegin: () => {\n const array = [];\n onValue(array);\n previousParents.push(currentParent);\n currentParent = array;\n currentProperty = null;\n },\n onArrayEnd: () => {\n currentParent = previousParents.pop();\n },\n onLiteralValue: onValue,\n onError: (error, offset, length) => {\n errors.push({ error, offset, length });\n }\n };\n visit(text, visitor, options);\n return currentParent[0];\n}\n/**\n * Parses the given text and returns a tree representation the JSON content. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.\n */\nexport function parseTree(text, errors = [], options = ParseOptions.DEFAULT) {\n let currentParent = { type: 'array', offset: -1, length: -1, children: [], parent: undefined }; // artificial root\n function ensurePropertyComplete(endOffset) {\n if (currentParent.type === 'property') {\n currentParent.length = endOffset - currentParent.offset;\n currentParent = currentParent.parent;\n }\n }\n function onValue(valueNode) {\n currentParent.children.push(valueNode);\n return valueNode;\n }\n const visitor = {\n onObjectBegin: (offset) => {\n currentParent = onValue({ type: 'object', offset, length: -1, parent: currentParent, children: [] });\n },\n onObjectProperty: (name, offset, length) => {\n currentParent = onValue({ type: 'property', offset, length: -1, parent: currentParent, children: [] });\n currentParent.children.push({ type: 'string', value: name, offset, length, parent: currentParent });\n },\n onObjectEnd: (offset, length) => {\n ensurePropertyComplete(offset + length); // in case of a missing value for a property: make sure property is complete\n currentParent.length = offset + length - currentParent.offset;\n currentParent = currentParent.parent;\n ensurePropertyComplete(offset + length);\n },\n onArrayBegin: (offset, length) => {\n currentParent = onValue({ type: 'array', offset, length: -1, parent: currentParent, children: [] });\n },\n onArrayEnd: (offset, length) => {\n currentParent.length = offset + length - currentParent.offset;\n currentParent = currentParent.parent;\n ensurePropertyComplete(offset + length);\n },\n onLiteralValue: (value, offset, length) => {\n onValue({ type: getNodeType(value), offset, length, parent: currentParent, value });\n ensurePropertyComplete(offset + length);\n },\n onSeparator: (sep, offset, length) => {\n if (currentParent.type === 'property') {\n if (sep === ':') {\n currentParent.colonOffset = offset;\n }\n else if (sep === ',') {\n ensurePropertyComplete(offset);\n }\n }\n },\n onError: (error, offset, length) => {\n errors.push({ error, offset, length });\n }\n };\n visit(text, visitor, options);\n const result = currentParent.children[0];\n if (result) {\n delete result.parent;\n }\n return result;\n}\n/**\n * Finds the node at the given path in a JSON DOM.\n */\nexport function findNodeAtLocation(root, path) {\n if (!root) {\n return undefined;\n }\n let node = root;\n for (let segment of path) {\n if (typeof segment === 'string') {\n if (node.type !== 'object' || !Array.isArray(node.children)) {\n return undefined;\n }\n let found = false;\n for (const propertyNode of node.children) {\n if (Array.isArray(propertyNode.children) && propertyNode.children[0].value === segment && propertyNode.children.length === 2) {\n node = propertyNode.children[1];\n found = true;\n break;\n }\n }\n if (!found) {\n return undefined;\n }\n }\n else {\n const index = segment;\n if (node.type !== 'array' || index < 0 || !Array.isArray(node.children) || index >= node.children.length) {\n return undefined;\n }\n node = node.children[index];\n }\n }\n return node;\n}\n/**\n * Gets the JSON path of the given JSON DOM node\n */\nexport function getNodePath(node) {\n if (!node.parent || !node.parent.children) {\n return [];\n }\n const path = getNodePath(node.parent);\n if (node.parent.type === 'property') {\n const key = node.parent.children[0].value;\n path.push(key);\n }\n else if (node.parent.type === 'array') {\n const index = node.parent.children.indexOf(node);\n if (index !== -1) {\n path.push(index);\n }\n }\n return path;\n}\n/**\n * Evaluates the JavaScript object of the given JSON DOM node\n */\nexport function getNodeValue(node) {\n switch (node.type) {\n case 'array':\n return node.children.map(getNodeValue);\n case 'object':\n const obj = Object.create(null);\n for (let prop of node.children) {\n const valueNode = prop.children[1];\n if (valueNode) {\n obj[prop.children[0].value] = getNodeValue(valueNode);\n }\n }\n return obj;\n case 'null':\n case 'string':\n case 'number':\n case 'boolean':\n return node.value;\n default:\n return undefined;\n }\n}\nexport function contains(node, offset, includeRightBound = false) {\n return (offset >= node.offset && offset < (node.offset + node.length)) || includeRightBound && (offset === (node.offset + node.length));\n}\n/**\n * Finds the most inner node at the given offset. If includeRightBound is set, also finds nodes that end at the given offset.\n */\nexport function findNodeAtOffset(node, offset, includeRightBound = false) {\n if (contains(node, offset, includeRightBound)) {\n const children = node.children;\n if (Array.isArray(children)) {\n for (let i = 0; i < children.length && children[i].offset <= offset; i++) {\n const item = findNodeAtOffset(children[i], offset, includeRightBound);\n if (item) {\n return item;\n }\n }\n }\n return node;\n }\n return undefined;\n}\n/**\n * Parses the given text and invokes the visitor functions for each object, array and literal reached.\n */\nexport function visit(text, visitor, options = ParseOptions.DEFAULT) {\n const _scanner = createScanner(text, false);\n // Important: Only pass copies of this to visitor functions to prevent accidental modification, and\n // to not affect visitor functions which stored a reference to a previous JSONPath\n const _jsonPath = [];\n // Depth of onXXXBegin() callbacks suppressed. onXXXEnd() decrements this if it isn't 0 already.\n // Callbacks are only called when this value is 0.\n let suppressedCallbacks = 0;\n function toNoArgVisit(visitFunction) {\n return visitFunction ? () => suppressedCallbacks === 0 && visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;\n }\n function toOneArgVisit(visitFunction) {\n return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;\n }\n function toOneArgVisitWithPath(visitFunction) {\n return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice()) : () => true;\n }\n function toBeginVisit(visitFunction) {\n return visitFunction ?\n () => {\n if (suppressedCallbacks > 0) {\n suppressedCallbacks++;\n }\n else {\n let cbReturn = visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice());\n if (cbReturn === false) {\n suppressedCallbacks = 1;\n }\n }\n }\n : () => true;\n }\n function toEndVisit(visitFunction) {\n return visitFunction ?\n () => {\n if (suppressedCallbacks > 0) {\n suppressedCallbacks--;\n }\n if (suppressedCallbacks === 0) {\n visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter());\n }\n }\n : () => true;\n }\n const onObjectBegin = toBeginVisit(visitor.onObjectBegin), onObjectProperty = toOneArgVisitWithPath(visitor.onObjectProperty), onObjectEnd = toEndVisit(visitor.onObjectEnd), onArrayBegin = toBeginVisit(visitor.onArrayBegin), onArrayEnd = toEndVisit(visitor.onArrayEnd), onLiteralValue = toOneArgVisitWithPath(visitor.onLiteralValue), onSeparator = toOneArgVisit(visitor.onSeparator), onComment = toNoArgVisit(visitor.onComment), onError = toOneArgVisit(visitor.onError);\n const disallowComments = options && options.disallowComments;\n const allowTrailingComma = options && options.allowTrailingComma;\n function scanNext() {\n while (true) {\n const token = _scanner.scan();\n switch (_scanner.getTokenError()) {\n case 4 /* ScanError.InvalidUnicode */:\n handleError(14 /* ParseErrorCode.InvalidUnicode */);\n break;\n case 5 /* ScanError.InvalidEscapeCharacter */:\n handleError(15 /* ParseErrorCode.InvalidEscapeCharacter */);\n break;\n case 3 /* ScanError.UnexpectedEndOfNumber */:\n handleError(13 /* ParseErrorCode.UnexpectedEndOfNumber */);\n break;\n case 1 /* ScanError.UnexpectedEndOfComment */:\n if (!disallowComments) {\n handleError(11 /* ParseErrorCode.UnexpectedEndOfComment */);\n }\n break;\n case 2 /* ScanError.UnexpectedEndOfString */:\n handleError(12 /* ParseErrorCode.UnexpectedEndOfString */);\n break;\n case 6 /* ScanError.InvalidCharacter */:\n handleError(16 /* ParseErrorCode.InvalidCharacter */);\n break;\n }\n switch (token) {\n case 12 /* SyntaxKind.LineCommentTrivia */:\n case 13 /* SyntaxKind.BlockCommentTrivia */:\n if (disallowComments) {\n handleError(10 /* ParseErrorCode.InvalidCommentToken */);\n }\n else {\n onComment();\n }\n break;\n case 16 /* SyntaxKind.Unknown */:\n handleError(1 /* ParseErrorCode.InvalidSymbol */);\n break;\n case 15 /* SyntaxKind.Trivia */:\n case 14 /* SyntaxKind.LineBreakTrivia */:\n break;\n default:\n return token;\n }\n }\n }\n function handleError(error, skipUntilAfter = [], skipUntil = []) {\n onError(error);\n if (skipUntilAfter.length + skipUntil.length > 0) {\n let token = _scanner.getToken();\n while (token !== 17 /* SyntaxKind.EOF */) {\n if (skipUntilAfter.indexOf(token) !== -1) {\n scanNext();\n break;\n }\n else if (skipUntil.indexOf(token) !== -1) {\n break;\n }\n token = scanNext();\n }\n }\n }\n function parseString(isValue) {\n const value = _scanner.getTokenValue();\n if (isValue) {\n onLiteralValue(value);\n }\n else {\n onObjectProperty(value);\n // add property name afterwards\n _jsonPath.push(value);\n }\n scanNext();\n return true;\n }\n function parseLiteral() {\n switch (_scanner.getToken()) {\n case 11 /* SyntaxKind.NumericLiteral */:\n const tokenValue = _scanner.getTokenValue();\n let value = Number(tokenValue);\n if (isNaN(value)) {\n handleError(2 /* ParseErrorCode.InvalidNumberFormat */);\n value = 0;\n }\n onLiteralValue(value);\n break;\n case 7 /* SyntaxKind.NullKeyword */:\n onLiteralValue(null);\n break;\n case 8 /* SyntaxKind.TrueKeyword */:\n onLiteralValue(true);\n break;\n case 9 /* SyntaxKind.FalseKeyword */:\n onLiteralValue(false);\n break;\n default:\n return false;\n }\n scanNext();\n return true;\n }\n function parseProperty() {\n if (_scanner.getToken() !== 10 /* SyntaxKind.StringLiteral */) {\n handleError(3 /* ParseErrorCode.PropertyNameExpected */, [], [2 /* SyntaxKind.CloseBraceToken */, 5 /* SyntaxKind.CommaToken */]);\n return false;\n }\n parseString(false);\n if (_scanner.getToken() === 6 /* SyntaxKind.ColonToken */) {\n onSeparator(':');\n scanNext(); // consume colon\n if (!parseValue()) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], [2 /* SyntaxKind.CloseBraceToken */, 5 /* SyntaxKind.CommaToken */]);\n }\n }\n else {\n handleError(5 /* ParseErrorCode.ColonExpected */, [], [2 /* SyntaxKind.CloseBraceToken */, 5 /* SyntaxKind.CommaToken */]);\n }\n _jsonPath.pop(); // remove processed property name\n return true;\n }\n function parseObject() {\n onObjectBegin();\n scanNext(); // consume open brace\n let needsComma = false;\n while (_scanner.getToken() !== 2 /* SyntaxKind.CloseBraceToken */ && _scanner.getToken() !== 17 /* SyntaxKind.EOF */) {\n if (_scanner.getToken() === 5 /* SyntaxKind.CommaToken */) {\n if (!needsComma) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], []);\n }\n onSeparator(',');\n scanNext(); // consume comma\n if (_scanner.getToken() === 2 /* SyntaxKind.CloseBraceToken */ && allowTrailingComma) {\n break;\n }\n }\n else if (needsComma) {\n handleError(6 /* ParseErrorCode.CommaExpected */, [], []);\n }\n if (!parseProperty()) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], [2 /* SyntaxKind.CloseBraceToken */, 5 /* SyntaxKind.CommaToken */]);\n }\n needsComma = true;\n }\n onObjectEnd();\n if (_scanner.getToken() !== 2 /* SyntaxKind.CloseBraceToken */) {\n handleError(7 /* ParseErrorCode.CloseBraceExpected */, [2 /* SyntaxKind.CloseBraceToken */], []);\n }\n else {\n scanNext(); // consume close brace\n }\n return true;\n }\n function parseArray() {\n onArrayBegin();\n scanNext(); // consume open bracket\n let isFirstElement = true;\n let needsComma = false;\n while (_scanner.getToken() !== 4 /* SyntaxKind.CloseBracketToken */ && _scanner.getToken() !== 17 /* SyntaxKind.EOF */) {\n if (_scanner.getToken() === 5 /* SyntaxKind.CommaToken */) {\n if (!needsComma) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], []);\n }\n onSeparator(',');\n scanNext(); // consume comma\n if (_scanner.getToken() === 4 /* SyntaxKind.CloseBracketToken */ && allowTrailingComma) {\n break;\n }\n }\n else if (needsComma) {\n handleError(6 /* ParseErrorCode.CommaExpected */, [], []);\n }\n if (isFirstElement) {\n _jsonPath.push(0);\n isFirstElement = false;\n }\n else {\n _jsonPath[_jsonPath.length - 1]++;\n }\n if (!parseValue()) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], [4 /* SyntaxKind.CloseBracketToken */, 5 /* SyntaxKind.CommaToken */]);\n }\n needsComma = true;\n }\n onArrayEnd();\n if (!isFirstElement) {\n _jsonPath.pop(); // remove array index\n }\n if (_scanner.getToken() !== 4 /* SyntaxKind.CloseBracketToken */) {\n handleError(8 /* ParseErrorCode.CloseBracketExpected */, [4 /* SyntaxKind.CloseBracketToken */], []);\n }\n else {\n scanNext(); // consume close bracket\n }\n return true;\n }\n function parseValue() {\n switch (_scanner.getToken()) {\n case 3 /* SyntaxKind.OpenBracketToken */:\n return parseArray();\n case 1 /* SyntaxKind.OpenBraceToken */:\n return parseObject();\n case 10 /* SyntaxKind.StringLiteral */:\n return parseString(true);\n default:\n return parseLiteral();\n }\n }\n scanNext();\n if (_scanner.getToken() === 17 /* SyntaxKind.EOF */) {\n if (options.allowEmptyContent) {\n return true;\n }\n handleError(4 /* ParseErrorCode.ValueExpected */, [], []);\n return false;\n }\n if (!parseValue()) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], []);\n return false;\n }\n if (_scanner.getToken() !== 17 /* SyntaxKind.EOF */) {\n handleError(9 /* ParseErrorCode.EndOfFileExpected */, [], []);\n }\n return true;\n}\n/**\n * Takes JSON with JavaScript-style comments and remove\n * them. Optionally replaces every none-newline character\n * of comments with a replaceCharacter\n */\nexport function stripComments(text, replaceCh) {\n let _scanner = createScanner(text), parts = [], kind, offset = 0, pos;\n do {\n pos = _scanner.getPosition();\n kind = _scanner.scan();\n switch (kind) {\n case 12 /* SyntaxKind.LineCommentTrivia */:\n case 13 /* SyntaxKind.BlockCommentTrivia */:\n case 17 /* SyntaxKind.EOF */:\n if (offset !== pos) {\n parts.push(text.substring(offset, pos));\n }\n if (replaceCh !== undefined) {\n parts.push(_scanner.getTokenValue().replace(/[^\\r\\n]/g, replaceCh));\n }\n offset = _scanner.getPosition();\n break;\n }\n } while (kind !== 17 /* SyntaxKind.EOF */);\n return parts.join('');\n}\nexport function getNodeType(value) {\n switch (typeof value) {\n case 'boolean': return 'boolean';\n case 'number': return 'number';\n case 'string': return 'string';\n case 'object': {\n if (!value) {\n return 'null';\n }\n else if (Array.isArray(value)) {\n return 'array';\n }\n return 'object';\n }\n default: return 'null';\n }\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n'use strict';\nimport * as formatter from './impl/format';\nimport * as edit from './impl/edit';\nimport * as scanner from './impl/scanner';\nimport * as parser from './impl/parser';\n/**\n * Creates a JSON scanner on the given text.\n * If ignoreTrivia is set, whitespaces or comments are ignored.\n */\nexport const createScanner = scanner.createScanner;\nexport var ScanError;\n(function (ScanError) {\n ScanError[ScanError[\"None\"] = 0] = \"None\";\n ScanError[ScanError[\"UnexpectedEndOfComment\"] = 1] = \"UnexpectedEndOfComment\";\n ScanError[ScanError[\"UnexpectedEndOfString\"] = 2] = \"UnexpectedEndOfString\";\n ScanError[ScanError[\"UnexpectedEndOfNumber\"] = 3] = \"UnexpectedEndOfNumber\";\n ScanError[ScanError[\"InvalidUnicode\"] = 4] = \"InvalidUnicode\";\n ScanError[ScanError[\"InvalidEscapeCharacter\"] = 5] = \"InvalidEscapeCharacter\";\n ScanError[ScanError[\"InvalidCharacter\"] = 6] = \"InvalidCharacter\";\n})(ScanError || (ScanError = {}));\nexport var SyntaxKind;\n(function (SyntaxKind) {\n SyntaxKind[SyntaxKind[\"OpenBraceToken\"] = 1] = \"OpenBraceToken\";\n SyntaxKind[SyntaxKind[\"CloseBraceToken\"] = 2] = \"CloseBraceToken\";\n SyntaxKind[SyntaxKind[\"OpenBracketToken\"] = 3] = \"OpenBracketToken\";\n SyntaxKind[SyntaxKind[\"CloseBracketToken\"] = 4] = \"CloseBracketToken\";\n SyntaxKind[SyntaxKind[\"CommaToken\"] = 5] = \"CommaToken\";\n SyntaxKind[SyntaxKind[\"ColonToken\"] = 6] = \"ColonToken\";\n SyntaxKind[SyntaxKind[\"NullKeyword\"] = 7] = \"NullKeyword\";\n SyntaxKind[SyntaxKind[\"TrueKeyword\"] = 8] = \"TrueKeyword\";\n SyntaxKind[SyntaxKind[\"FalseKeyword\"] = 9] = \"FalseKeyword\";\n SyntaxKind[SyntaxKind[\"StringLiteral\"] = 10] = \"StringLiteral\";\n SyntaxKind[SyntaxKind[\"NumericLiteral\"] = 11] = \"NumericLiteral\";\n SyntaxKind[SyntaxKind[\"LineCommentTrivia\"] = 12] = \"LineCommentTrivia\";\n SyntaxKind[SyntaxKind[\"BlockCommentTrivia\"] = 13] = \"BlockCommentTrivia\";\n SyntaxKind[SyntaxKind[\"LineBreakTrivia\"] = 14] = \"LineBreakTrivia\";\n SyntaxKind[SyntaxKind[\"Trivia\"] = 15] = \"Trivia\";\n SyntaxKind[SyntaxKind[\"Unknown\"] = 16] = \"Unknown\";\n SyntaxKind[SyntaxKind[\"EOF\"] = 17] = \"EOF\";\n})(SyntaxKind || (SyntaxKind = {}));\n/**\n * For a given offset, evaluate the location in the JSON document. Each segment in the location path is either a property name or an array index.\n */\nexport const getLocation = parser.getLocation;\n/**\n * Parses the given text and returns the object the JSON content represents. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.\n * Therefore, always check the errors list to find out if the input was valid.\n */\nexport const parse = parser.parse;\n/**\n * Parses the given text and returns a tree representation the JSON content. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.\n */\nexport const parseTree = parser.parseTree;\n/**\n * Finds the node at the given path in a JSON DOM.\n */\nexport const findNodeAtLocation = parser.findNodeAtLocation;\n/**\n * Finds the innermost node at the given offset. If includeRightBound is set, also finds nodes that end at the given offset.\n */\nexport const findNodeAtOffset = parser.findNodeAtOffset;\n/**\n * Gets the JSON path of the given JSON DOM node\n */\nexport const getNodePath = parser.getNodePath;\n/**\n * Evaluates the JavaScript object of the given JSON DOM node\n */\nexport const getNodeValue = parser.getNodeValue;\n/**\n * Parses the given text and invokes the visitor functions for each object, array and literal reached.\n */\nexport const visit = parser.visit;\n/**\n * Takes JSON with JavaScript-style comments and remove\n * them. Optionally replaces every none-newline character\n * of comments with a replaceCharacter\n */\nexport const stripComments = parser.stripComments;\nexport var ParseErrorCode;\n(function (ParseErrorCode) {\n ParseErrorCode[ParseErrorCode[\"InvalidSymbol\"] = 1] = \"InvalidSymbol\";\n ParseErrorCode[ParseErrorCode[\"InvalidNumberFormat\"] = 2] = \"InvalidNumberFormat\";\n ParseErrorCode[ParseErrorCode[\"PropertyNameExpected\"] = 3] = \"PropertyNameExpected\";\n ParseErrorCode[ParseErrorCode[\"ValueExpected\"] = 4] = \"ValueExpected\";\n ParseErrorCode[ParseErrorCode[\"ColonExpected\"] = 5] = \"ColonExpected\";\n ParseErrorCode[ParseErrorCode[\"CommaExpected\"] = 6] = \"CommaExpected\";\n ParseErrorCode[ParseErrorCode[\"CloseBraceExpected\"] = 7] = \"CloseBraceExpected\";\n ParseErrorCode[ParseErrorCode[\"CloseBracketExpected\"] = 8] = \"CloseBracketExpected\";\n ParseErrorCode[ParseErrorCode[\"EndOfFileExpected\"] = 9] = \"EndOfFileExpected\";\n ParseErrorCode[ParseErrorCode[\"InvalidCommentToken\"] = 10] = \"InvalidCommentToken\";\n ParseErrorCode[ParseErrorCode[\"UnexpectedEndOfComment\"] = 11] = \"UnexpectedEndOfComment\";\n ParseErrorCode[ParseErrorCode[\"UnexpectedEndOfString\"] = 12] = \"UnexpectedEndOfString\";\n ParseErrorCode[ParseErrorCode[\"UnexpectedEndOfNumber\"] = 13] = \"UnexpectedEndOfNumber\";\n ParseErrorCode[ParseErrorCode[\"InvalidUnicode\"] = 14] = \"InvalidUnicode\";\n ParseErrorCode[ParseErrorCode[\"InvalidEscapeCharacter\"] = 15] = \"InvalidEscapeCharacter\";\n ParseErrorCode[ParseErrorCode[\"InvalidCharacter\"] = 16] = \"InvalidCharacter\";\n})(ParseErrorCode || (ParseErrorCode = {}));\nexport function printParseErrorCode(code) {\n switch (code) {\n case 1 /* ParseErrorCode.InvalidSymbol */: return 'InvalidSymbol';\n case 2 /* ParseErrorCode.InvalidNumberFormat */: return 'InvalidNumberFormat';\n case 3 /* ParseErrorCode.PropertyNameExpected */: return 'PropertyNameExpected';\n case 4 /* ParseErrorCode.ValueExpected */: return 'ValueExpected';\n case 5 /* ParseErrorCode.ColonExpected */: return 'ColonExpected';\n case 6 /* ParseErrorCode.CommaExpected */: return 'CommaExpected';\n case 7 /* ParseErrorCode.CloseBraceExpected */: return 'CloseBraceExpected';\n case 8 /* ParseErrorCode.CloseBracketExpected */: return 'CloseBracketExpected';\n case 9 /* ParseErrorCode.EndOfFileExpected */: return 'EndOfFileExpected';\n case 10 /* ParseErrorCode.InvalidCommentToken */: return 'InvalidCommentToken';\n case 11 /* ParseErrorCode.UnexpectedEndOfComment */: return 'UnexpectedEndOfComment';\n case 12 /* ParseErrorCode.UnexpectedEndOfString */: return 'UnexpectedEndOfString';\n case 13 /* ParseErrorCode.UnexpectedEndOfNumber */: return 'UnexpectedEndOfNumber';\n case 14 /* ParseErrorCode.InvalidUnicode */: return 'InvalidUnicode';\n case 15 /* ParseErrorCode.InvalidEscapeCharacter */: return 'InvalidEscapeCharacter';\n case 16 /* ParseErrorCode.InvalidCharacter */: return 'InvalidCharacter';\n }\n return '<unknown ParseErrorCode>';\n}\n/**\n * Computes the edit operations needed to format a JSON document.\n *\n * @param documentText The input text\n * @param range The range to format or `undefined` to format the full content\n * @param options The formatting options\n * @returns The edit operations describing the formatting changes to the original document following the format described in {@linkcode EditResult}.\n * To apply the edit operations to the input, use {@linkcode applyEdits}.\n */\nexport function format(documentText, range, options) {\n return formatter.format(documentText, range, options);\n}\n/**\n * Computes the edit operations needed to modify a value in the JSON document.\n *\n * @param documentText The input text\n * @param path The path of the value to change. The path represents either to the document root, a property or an array item.\n * If the path points to an non-existing property or item, it will be created.\n * @param value The new value for the specified property or item. If the value is undefined,\n * the property or item will be removed.\n * @param options Options\n * @returns The edit operations describing the changes to the original document, following the format described in {@linkcode EditResult}.\n * To apply the edit operations to the input, use {@linkcode applyEdits}.\n */\nexport function modify(text, path, value, options) {\n return edit.setProperty(text, path, value, options);\n}\n/**\n * Applies edits to an input string.\n * @param text The input text\n * @param edits Edit operations following the format described in {@linkcode EditResult}.\n * @returns The text with the applied edits.\n * @throws An error if the edit operations are not well-formed as described in {@linkcode EditResult}.\n */\nexport function applyEdits(text, edits) {\n let sortedEdits = edits.slice(0).sort((a, b) => {\n const diff = a.offset - b.offset;\n if (diff === 0) {\n return a.length - b.length;\n }\n return diff;\n });\n let lastModifiedOffset = text.length;\n for (let i = sortedEdits.length - 1; i >= 0; i--) {\n let e = sortedEdits[i];\n if (e.offset + e.length <= lastModifiedOffset) {\n text = edit.applyEdit(text, e);\n }\n else {\n throw new Error('Overlapping edit');\n }\n lastModifiedOffset = e.offset;\n }\n return text;\n}\n","import { beacon } from \"./client\";\nimport { DWELL_THRESHOLD_MS } from \"./constants\";\nimport { debugLog } from \"./debug\";\nimport { adCachePath, pendingTurnPath, terminalHeartbeatPath } from \"./paths\";\nimport { readJson, writeJsonAtomic } from \"./store\";\nimport type {\n\tTAd,\n\tTAdCache,\n\tTCachedAd,\n\tTCachedAdSet,\n\tTPendingTurn,\n} from \"./types\";\n\n/**\n * How stale a terminal heartbeat can be and still count as \"a real terminal\n * is active right now\". Claude Code re-invokes `statusLine` roughly every\n * 300ms while a real terminal is actually rendering it, so anything within\n * a few seconds is a live terminal; anything older means no terminal has\n * rendered recently, so this hook invocation almost certainly belongs to the\n * IDE chat panel instead (the only other supported surface, and one that\n * never touches this file at all).\n */\nconst _TERMINAL_HEARTBEAT_STALE_MS = 5_000;\n\n/**\n * Guards every read of a cache entry against a shape this version doesn't\n * recognize -- treated exactly like \"no entry\" (`null`/no-op), never a\n * crash. `TCachedAdSet` replaced an older single-ad shape earlier this same\n * project; a machine whose `~/.kili/ad-cache.json` still has an entry from\n * before that (an old extension build that never got a chance to overwrite\n * it, a partially-written file, anything) has `entry.ads === undefined`,\n * and every function here used to reach straight for `entry.ads.length`\n * with nothing checking that first -- confirmed live: `TypeError: Cannot\n * read properties of undefined (reading 'length')` in `advanceRotation`,\n * crashing the extension host on a fresh install. `entry` is read as\n * `unknown` on purpose so this stays the one place that has to know what a\n * valid entry actually looks like.\n */\nfunction _isValidEntry(entry: unknown): entry is TCachedAdSet {\n\treturn (\n\t\ttypeof entry === \"object\" &&\n\t\tentry !== null &&\n\t\tArray.isArray((entry as TCachedAdSet).ads) &&\n\t\tArray.isArray((entry as TCachedAdSet).perAd) &&\n\t\ttypeof (entry as TCachedAdSet).currentIndex === \"number\"\n\t);\n}\n\n/** Called by `statusline.ts` on every invocation -- see `terminalHeartbeatPath`\n * and `isTerminalActive`. */\nexport function touchTerminalHeartbeat(): void {\n\twriteJsonAtomic(terminalHeartbeatPath(), { ts: Date.now() });\n}\n\n/**\n * Whether a real terminal is currently rendering `statusLine`, inferred from\n * how recently `statusline.ts` last ran. `hook.ts` uses this to decide which\n * *single* spinner placement a turn's impression belongs to -- terminal or\n * IDE chat panel, never both. Before this existed, every turn unconditionally\n * settled impressions for both `TERMINAL_SPINNER` and `EXTENSION_SPINNER`,\n * so a user looking at only one of the two surfaces was silently billed for\n * a \"view\" of the other one too, which nothing was ever rendering.\n */\nexport function isTerminalActive(): boolean {\n\tconst heartbeat = readJson<{ ts: number } | null>(\n\t\tterminalHeartbeatPath(),\n\t\tnull,\n\t);\n\tif (!heartbeat) return false;\n\treturn Date.now() - heartbeat.ts < _TERMINAL_HEARTBEAT_STALE_MS;\n}\n\n/**\n * Store a freshly-fetched rotation set for a placement, replacing whatever\n * was there. `api.kili` now serves every eligible ad to every requested\n * placement (see `ads.service.ts`'s `_serveSelectedAds`), so a placement\n * with a live process behind it can rotate through more than one ad across a\n * single long turn instead of showing one static ad the whole time. Starts\n * at `currentIndex: 0` -- the first ad in the (server-shuffled) list is\n * whatever's shown immediately, before any rotation tick has run.\n */\nexport function putAd(placementId: string, ads: TAd[]): TCachedAdSet {\n\tconst cache = readJson<TAdCache>(adCachePath(), {});\n\tconst entry: TCachedAdSet = {\n\t\tads,\n\t\tcurrentIndex: 0,\n\t\trotationStartedAt: Date.now(),\n\t\tperAd: ads.map(() => ({ firstSeenAt: null, impressionFiredAt: null })),\n\t};\n\tcache[placementId] = entry;\n\twriteJsonAtomic(adCachePath(), cache);\n\t// KILI_DEBUG=1 only -- a rotation set of size 1 means there's genuinely\n\t// nothing to rotate through this turn (only one eligible/relevant ad),\n\t// not a bug in the rotation timer itself. This is the fastest way to\n\t// tell \"rotation isn't firing\" apart from \"rotation has nothing to do\".\n\tdebugLog(\"putAd\", { placementId, adCount: ads.length });\n\treturn entry;\n}\n\n/** The currently-active ad for a placement, projected out of its rotation\n * set -- callers that only care about \"what's on screen right now\" (e.g.\n * `extension.ts`'s `Kili: Show Status`) never need to know rotation sets\n * exist at all. */\nexport function getAd(placementId: string): TCachedAd | null {\n\tconst cache = readJson<TAdCache>(adCachePath(), {});\n\tconst entry = cache[placementId];\n\tif (!_isValidEntry(entry) || entry.ads.length === 0) return null;\n\tconst dwell = entry.perAd[entry.currentIndex];\n\treturn {\n\t\tad: entry.ads[entry.currentIndex],\n\t\tfetchedAt: entry.rotationStartedAt,\n\t\tfirstSeenAt: dwell?.firstSeenAt ?? null,\n\t\timpressionFiredAt: dwell?.impressionFiredAt ?? null,\n\t};\n}\n\n/**\n * Called every time a directly-rendered, repeatedly-polled surface (the\n * terminal status line, invoked by Claude Code roughly every 300ms) actually\n * paints the *currently-active* ad in a placement's rotation set. Tracks\n * that one ad's own continuous dwell and fires `impUrl` exactly once, the\n * moment it's been visible for `DWELL_THRESHOLD_MS` -- never before, never\n * twice. Needs at least two calls to actually fire (first arms\n * `firstSeenAt`, a later one claims it) -- fine for a surface that's polled\n * every 300ms, but see `claimCurrentImpression` for a placement that isn't\n * (like the extension spinner rotation timer, which writes a new ad once\n * per interval rather than being polled).\n */\nexport async function markRenderedAndClaimImpression(\n\tplacementId: string,\n): Promise<void> {\n\tconst cache = readJson<TAdCache>(adCachePath(), {});\n\tconst entry = cache[placementId];\n\tif (!_isValidEntry(entry) || entry.ads.length === 0) return;\n\tconst dwell = entry.perAd[entry.currentIndex];\n\tif (!dwell || dwell.impressionFiredAt) return;\n\n\tconst now = Date.now();\n\tif (dwell.firstSeenAt === null) {\n\t\tdwell.firstSeenAt = now;\n\t\twriteJsonAtomic(adCachePath(), cache);\n\t\treturn;\n\t}\n\n\tif (now - dwell.firstSeenAt < DWELL_THRESHOLD_MS) return;\n\n\tdwell.impressionFiredAt = now;\n\twriteJsonAtomic(adCachePath(), cache);\n\tawait beacon(entry.ads[entry.currentIndex].impUrl);\n}\n\n/**\n * Immediately fires the impression for a placement's currently-active ad, if\n * not already fired -- for callers that write a new ad once and don't get a\n * natural second \"render tick\" to satisfy `markRenderedAndClaimImpression`'s\n * arm-then-fire pattern. `extension.ts`'s turn-start fetch is the one\n * caller: it fetches a fresh ad the moment a new turn begins and writes it\n * once, and that single write is the whole \"render\" this ad ever gets from\n * our side before the next turn replaces it. Safe given `DWELL_THRESHOLD_MS\n * = 0`: \"shown is enough\" (see that constant's doc comment) already means\n * there's no minimum dwell worth waiting out here, so firing on first sight\n * is exactly the documented policy, not a shortcut around it.\n */\nexport async function claimCurrentImpression(\n\tplacementId: string,\n): Promise<void> {\n\tconst cache = readJson<TAdCache>(adCachePath(), {});\n\tconst entry = cache[placementId];\n\tif (!_isValidEntry(entry) || entry.ads.length === 0) return;\n\tconst dwell = entry.perAd[entry.currentIndex];\n\tif (!dwell || dwell.impressionFiredAt) return;\n\n\tconst now = Date.now();\n\tdwell.impressionFiredAt = now;\n\tif (dwell.firstSeenAt === null) dwell.firstSeenAt = now;\n\twriteJsonAtomic(adCachePath(), cache);\n\tawait beacon(entry.ads[entry.currentIndex].impUrl);\n}\n\n/** Written by `UserPromptSubmit`, read (and cleared) by `Stop` -- the proxy\n * pair that infers a spinner-verb impression we can't directly observe. */\nexport function startPendingTurn(pending: TPendingTurn): void {\n\twriteJsonAtomic(pendingTurnPath(), pending);\n}\n\nexport function takePendingTurn(): TPendingTurn | null {\n\tconst pending = readJson<TPendingTurn | null>(pendingTurnPath(), null);\n\tif (pending) writeJsonAtomic(pendingTurnPath(), null);\n\treturn pending;\n}\n\n/**\n * Non-consuming check for whether a turn is currently in flight (started by\n * `UserPromptSubmit`, not yet settled by `Stop`). `extension.ts`'s periodic\n * refresh timer uses this to skip itself mid-turn: firing anyway would\n * overwrite `claudeCode.spinnerVerbs` with a newly-fetched, likely different\n * ad while the turn's spinner is still showing the one from turn start --\n * a visible ad swap partway through, with the first ad's impression never\n * getting a full dwell window and the second one starting its dwell clock\n * late. `hook.ts`'s own per-turn refresh already covers keeping the ad fresh\n * at each turn boundary, so skipping the idle timer mid-turn loses nothing.\n */\nexport function hasPendingTurn(): boolean {\n\treturn readJson<TPendingTurn | null>(pendingTurnPath(), null) !== null;\n}\n\n/**\n * Non-consuming read of the full pending-turn record, not just whether one\n * exists -- `extension.ts` uses `startedAt` here to tell \"still the same\n * turn I already fetched an ad for\" apart from \"a genuinely new turn just\n * started\", since this file gets polled repeatedly over a turn's lifetime,\n * not read once. Returns `null` exactly when `hasPendingTurn` would be\n * `false`.\n */\nexport function peekPendingTurn(): TPendingTurn | null {\n\treturn readJson<TPendingTurn | null>(pendingTurnPath(), null);\n}\n\n/**\n * `Stop`-side half: if the turn that just ended ran at least\n * `DWELL_THRESHOLD_MS` -- meaning the spinner, whatever it showed, was on\n * screen that whole time -- fire the impression for whichever ad is\n * *currently active* in each spinner-text placement's rotation set (terminal\n * spinner, extension sidebar spinner). A turn shorter than the threshold\n * means the spinner barely showed, so none of them qualify.\n *\n * The terminal spinner never rotates mid-turn (no persistent process behind\n * it to drive a timer -- see `extension.ts`'s rotation timer doc comment),\n * so this is its *only* impression trigger, same as before: one ad, one\n * impression, whole turn. The extension spinner *does* rotate, driven by\n * `extension.ts`'s timer, which already fires an impression per ad the\n * moment it's shown (`claimCurrentImpression`) -- this is just a\n * safety net for whatever's current when the turn actually ends, guarded by\n * the same `impressionFiredAt` check so it can never double-bill an ad the\n * rotation timer already claimed.\n */\nexport async function settlePendingTurn(): Promise<void> {\n\tconst pending = takePendingTurn();\n\tif (!pending) {\n\t\tdebugLog(\"settlePendingTurn: nothing pending\");\n\t\treturn;\n\t}\n\tconst dwellMs = Date.now() - pending.startedAt;\n\tif (dwellMs < DWELL_THRESHOLD_MS) {\n\t\tdebugLog(\"settlePendingTurn: turn too short\", {\n\t\t\tdwellMs,\n\t\t\tthreshold: DWELL_THRESHOLD_MS,\n\t\t});\n\t\treturn;\n\t}\n\n\tconst cache = readJson<TAdCache>(adCachePath(), {});\n\tlet changed = false;\n\tconst toBeacon: string[] = [];\n\tconst decisions: Record<string, string> = {};\n\tfor (const placementId of pending.placementIds) {\n\t\tconst entry = cache[placementId];\n\t\tif (!_isValidEntry(entry) || entry.ads.length === 0) {\n\t\t\tdecisions[placementId] = \"no cached rotation set\";\n\t\t\tcontinue;\n\t\t}\n\t\tconst dwell = entry.perAd[entry.currentIndex];\n\t\tif (!dwell || dwell.impressionFiredAt) {\n\t\t\tdecisions[placementId] = \"already fired\";\n\t\t\tcontinue;\n\t\t}\n\t\tdwell.impressionFiredAt = Date.now();\n\t\tchanged = true;\n\t\tconst impUrl = entry.ads[entry.currentIndex].impUrl;\n\t\tif (impUrl) toBeacon.push(impUrl);\n\t\tdecisions[placementId] = \"fired\";\n\t}\n\tdebugLog(\"settlePendingTurn\", {\n\t\tplacementIds: pending.placementIds,\n\t\tdwellMs,\n\t\tdecisions,\n\t});\n\tif (changed) writeJsonAtomic(adCachePath(), cache);\n\tawait Promise.all(toBeacon.map((url) => beacon(url)));\n}\n","import { randomUUID } from \"node:crypto\";\nimport { DEFAULT_API_URL, DEFAULT_WEB_URL } from \"./constants\";\nimport { runtimeConfigPath } from \"./paths\";\nimport { readJson, writeJsonAtomic } from \"./store\";\nimport type { TRuntimeConfig } from \"./types\";\n\n/**\n * `~/.kili/config.json` holds one thing: the extension's resolved config,\n * read back by `hook.ts` and `statusline.ts` (both spawned fresh per call,\n * neither able to read VS Code's own configuration API). `installId` lives\n * in the same file so it survives independently of whether a key has been\n * set yet -- `ensureInstallId` merges rather than overwrites so it never\n * clobbers a config the extension already wrote.\n *\n * `apiKey` survives an *implicit* re-sign-in (e.g. `npx @kili-ai/install`\n * run again on a device that already has one) -- that's what\n * `readRuntimeConfig`/`readCachedApiKey` short-circuiting is for, and it's\n * what keeps a non-interactive re-run from minting a duplicate key/surface\n * every time (see `pkg.install.kili/src/terminal.ts`'s doc comment: this\n * used to mint 37 near-duplicate surfaces for one account before that cache\n * existed).\n *\n * An *explicit* \"Kili: Sign Out\", though, clears it here too (see\n * `extension.ts`'s `_handleSignOut` -> `clearCachedApiKey`) -- signing out is\n * a deliberate action, not an accidental re-run, and the whole point of it is\n * to let the next sign-in be a real one: a different account, or a\n * deliberately fresh key for this one. The old key's plaintext is gone for\n * good either way (the server only ever stores a one-way hash -- see\n * `db/schema.ts`'s `publisherSurfaces.keyHash`), so there is no \"recover it\n * instead of minting a new one\" option here regardless.\n */\ntype TStoredConfig = Partial<TRuntimeConfig> & { installId?: string };\n\nfunction _read(): TStoredConfig {\n\treturn readJson<TStoredConfig>(runtimeConfigPath(), {});\n}\n\n/** A stable anonymous id for this machine's install -- never tied to an\n * account, just enough to keep one dwell/frequency bookkeeping identity. */\nexport function ensureInstallId(): string {\n\tconst existing = _read();\n\tif (existing.installId) return existing.installId;\n\tconst installId = randomUUID();\n\twriteJsonAtomic(runtimeConfigPath(), { ...existing, installId });\n\treturn installId;\n}\n\nexport function toSessionId(claudeSessionId: string | undefined): string {\n\treturn claudeSessionId ?? randomUUID();\n}\n\nexport function resolveRuntimeConfig(input: {\n\tapiKey: string;\n\tapiUrl?: string;\n\twebUrl?: string;\n\tenabled?: boolean;\n}): TRuntimeConfig {\n\treturn {\n\t\tapiKey: input.apiKey,\n\t\tapiUrl: input.apiUrl ?? DEFAULT_API_URL,\n\t\twebUrl: input.webUrl ?? DEFAULT_WEB_URL,\n\t\tenabled: input.enabled ?? true,\n\t\tinstallId: ensureInstallId(),\n\t\twebviewPatchedEditors: _read().webviewPatchedEditors ?? [],\n\t};\n}\n\nexport function writeRuntimeConfig(config: TRuntimeConfig): void {\n\twriteJsonAtomic(runtimeConfigPath(), config);\n}\n\n/** Merge-only update of just the patch-state list -- called by\n * `extension.ts` after `webviewPatch.ts` runs, separately from the rest of\n * `resolveRuntimeConfig`'s inputs so it never has to round-trip through\n * VS Code's settings to persist this. */\nexport function writeWebviewPatchedEditors(editorFolders: string[]): void {\n\tconst existing = _read();\n\twriteJsonAtomic(runtimeConfigPath(), {\n\t\t...existing,\n\t\twebviewPatchedEditors: editorFolders,\n\t});\n}\n\n/**\n * Clears the cached key on an explicit \"Kili: Sign Out\" -- see this file's\n * top doc comment for why this is scoped to the explicit sign-out path only,\n * never called from the implicit re-sign-in short-circuit. Everything else\n * in the file (`installId`, `webviewPatchedEditors`) is preserved: signing\n * out doesn't mean forgetting this device, just forgetting who's signed in\n * on it.\n */\nexport function clearCachedApiKey(): void {\n\tconst existing = _read();\n\twriteJsonAtomic(runtimeConfigPath(), { ...existing, apiKey: undefined });\n}\n\nexport function readRuntimeConfig(): TRuntimeConfig | null {\n\tconst stored = _read();\n\tif (!stored.apiKey || !stored.apiUrl || !stored.installId) return null;\n\treturn {\n\t\tapiKey: stored.apiKey,\n\t\tapiUrl: stored.apiUrl,\n\t\twebUrl: stored.webUrl ?? DEFAULT_WEB_URL,\n\t\tenabled: stored.enabled ?? true,\n\t\tinstallId: stored.installId,\n\t\twebviewPatchedEditors: stored.webviewPatchedEditors ?? [],\n\t};\n}\n","import {\n\texistsSync,\n\treadFileSync,\n\treaddirSync,\n\tstatSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\n/**\n * Patches Claude Code's own installed webview bundle so the spinner-verb\n * text can render a real clickable link -- something no supported setting\n * can do. Confirmed by reading the shipped source: `spinnerVerbsConfig`'s\n * verb text is rendered straight into a plain `<span>`'s `children`, with\n * no markdown/link parsing anywhere in that path (see `copy.ts`'s\n * `spinnerVerb()` doc comment). This is the deliberate, user-approved\n * exception to this package's \"official settings only, no patching\"\n * design -- explicit, disclosed in the consent prompt, and reversible.\n *\n * This WILL break whenever Claude Code ships a new webview build: every\n * `_ANCHOR` below is the EXACT, complete minified render function, copied\n * byte for byte from a real shipped file, not reconstructed from memory.\n * `readdirSync`ing for `anthropic.claude-code-*` finds whatever version is\n * actually installed; a version whose bundle doesn't match any known\n * anchor is left completely untouched, with a clear log line -- never\n * partially patched, never guessed at.\n */\n\nconst _MARKER = \"__kiliSpinnerLinkPatch\";\nconst _BACKUP_SUFFIX = \".kili-orig\";\n\ntype TAnchor = { version: string; find: string; replace: string };\n\n// One entry per verified Claude Code webview build. Each pair is the\n// M30/Mot-equivalent spinner-render component, unmodified except for the\n// inserted link-lookup logic -- everything else byte-identical to the\n// original, so a failed match never leaves a half-applied patch.\n//\n// Every `replace` also inserts one clause the original does not have:\n// `if(!Q.includes(H))H=Q[0]` (names vary per build). This fixes a real,\n// user-visible bug, and it is worth understanding before touching it.\n//\n// The component draws `H`, which comes from `useState`, and only ever\n// refreshes on Claude's own 2s/3s/5s re-pick timer. But the verb list `Q`\n// and the width `Z = max(verb.length)` are `useMemo`s keyed on the config,\n// so they update the instant a new ad is written. That leaves a window --\n// up to 5 seconds -- where the component renders the PREVIOUS turn's verb\n// at the NEW verb's width, and three separate symptoms all fall out of it:\n// 1. the previous ad stays on screen after a new turn starts;\n// 2. `rc0(H+\"...\", Z+3)` truncates that stale, longer text down to the\n// new, shorter width -- confirmed live, `[BOB: The Bank of Bitcoin]`\n// (26 chars) rendered as `[BOB: The Bank o`;\n// 3. the link and logo vanish, because the memo already cleared and\n// refilled the label->link map for the new list, so the stale `H` is\n// not a key in it and the component falls back to a plain `<span>`.\n// Clamping `H` into the current list makes all three impossible: the drawn\n// verb is always one the width was computed from, and always one the map\n// has an entry for. It is deliberately placed BEFORE the `\"Compacting\"`\n// override, which is intentionally not a member of the list.\nconst _ANCHORS: TAnchor[] = [\n\t{\n\t\tversion: \"2.1.258\",\n\t\tfind: 'function od0($){if(!$)return KH1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:KH1;return[...KH1,...$.verbs]}function s$0({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=C2(()=>od0(X),[X]),Z=C2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=J1(0),[z,U]=J1(()=>mi(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%a$0.length)},120);return()=>clearInterval(W)},[]),Vy(()=>{U(mi(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(Y===\"compacting\")H=\"Compacting\";let B=td0(H+\"...\",Z+3);return E(\"div\",{className:gi.container,\"data-permission-mode\":J,children:[D(\"span\",{\"aria-hidden\":\"true\",className:gi.icon,style:{fontSize:`${$}px`},children:a$0[G]}),D(\"span\",{\"aria-hidden\":\"true\",className:gi.text,children:B}),D(\"span\",{className:YN.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}',\n\t\treplace: `var ${_MARKER}=new Map();var __kiliLastLog=\"\";var __kiliLastGeom=\"\";function _kiliLog(o){try{var s=JSON.stringify(o);if(s===__kiliLastLog)return;__kiliLastLog=s;console.log(\"[kili]\",o)}catch(e){}}function _kiliParseLink(raw){let i=raw.indexOf(\"\\\\u0001\");if(i<0)return null;let rest=raw.slice(i+1);let j2=rest.indexOf(\"\\\\u0001\");return j2<0?{label:raw.slice(0,i),url:rest,logo:null}:{label:raw.slice(0,i),url:rest.slice(0,j2),logo:rest.slice(j2+1)}}function od0($){if(!$)return KH1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:KH1;return[...KH1,...$.verbs]}function s$0({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=C2(()=>{${_MARKER}.clear();return od0(X).map((raw)=>{let p=_kiliParseLink(raw);if(p){${_MARKER}.set(p.label,{url:p.url,logo:p.logo});return p.label}return raw})},[X]),Z=C2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=J1(0),[z,U]=J1(()=>mi(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%a$0.length)},120);return()=>clearInterval(W)},[]),Vy(()=>{U(mi(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(!Q.includes(H))H=Q[0];if(Y===\"compacting\")H=\"Compacting\";let B=H+\"...\",K=${_MARKER}.get(H);_kiliLog({labels:Q,width:Z,drawn:H,wasStale:!Q.includes(z),linked:!!K,hasLogo:!!(K&&K.logo)});return E(\"div\",{className:gi.container,style:{overflow:\"visible\",maxWidth:\"none\",width:\"auto\",flexWrap:\"nowrap\"},\"data-permission-mode\":J,children:[D(\"span\",{\"aria-hidden\":\"true\",className:gi.icon,style:{fontSize:\\`\\${$}px\\`},children:a$0[G]}),K?D(\"a\",{ref:(el)=>{if(!el)return;try{var sel=[],q=el.parentElement;for(var i=0;i<8&&q;i++){var qr=q.getBoundingClientRect();if(qr.height>80)break;var cn=(typeof q.className===\"string\"?q.className:\"\").trim();if(cn)sel.push(\".\"+cn.split(/\\\\s+/).join(\".\"));q=q.parentElement}if(sel.length){var id=\"__kiliUnclip\",st=document.getElementById(id);if(!st){st=document.createElement(\"style\");st.id=id;document.head.appendChild(st)}var css=sel.join(\",\")+\"{overflow:visible!important;max-width:none!important;min-width:0!important;flex-shrink:0!important;text-overflow:clip!important;white-space:nowrap!important;animation:none!important;transition:none!important}\";if(st.textContent!==css)st.textContent=css}setTimeout(function(){try{var o=[],n=el;for(var k=0;k<8&&n;k++){var c=getComputedStyle(n),r=n.getBoundingClientRect();o.push(k+\":\"+n.tagName+\" w=\"+Math.round(r.width)+\" h=\"+Math.round(r.height)+\" sw=\"+n.scrollWidth+\" tlen=\"+((n.textContent||\"\").length)+\" anim=\"+c.animationName+\" ovf=\"+c.overflow);n=n.parentElement}var g=o.join(\" | \");if(g!==__kiliLastGeom){__kiliLastGeom=g;console.log(\"[kili-geom]\",g)}}catch(e){}},50)}catch(e){}},\"aria-hidden\":\"true\",className:gi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},href:K.url,target:\"_blank\",rel:\"noopener noreferrer\",children:[K.logo?D(\"img\",{src:K.logo,alt:\"\",style:{width:\"14px\",height:\"14px\",borderRadius:\"3px\",objectFit:\"cover\",verticalAlign:\"middle\",marginRight:\"4px\"}}):null,B]}):D(\"span\",{\"aria-hidden\":\"true\",className:gi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},children:B}),D(\"span\",{className:YN.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}`,\n\t},\n\t{\n\t\tversion: \"2.1.251\",\n\t\tfind: 'function ac0($){if(!$)return TV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:TV1;return[...TV1,...$.verbs]}function L30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=t2(()=>ac0(X),[X]),Z=t2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Ki(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%R30.length)},120);return()=>clearInterval(W)},[]),sk(()=>{U(Ki(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(Y===\"compacting\")H=\"Compacting\";let B=rc0(H+\"...\",Z+3);return E(\"div\",{className:Fi.container,\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Fi.icon,style:{fontSize:`${$}px`},children:R30[G]}),j(\"span\",{\"aria-hidden\":\"true\",className:Fi.text,children:B}),j(\"span\",{className:aO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}',\n\t\treplace: `var ${_MARKER}=new Map();var __kiliLastLog=\"\";var __kiliLastGeom=\"\";function _kiliLog(o){try{var s=JSON.stringify(o);if(s===__kiliLastLog)return;__kiliLastLog=s;console.log(\"[kili]\",o)}catch(e){}}function _kiliParseLink(raw){let i=raw.indexOf(\"\\\\u0001\");if(i<0)return null;let rest=raw.slice(i+1);let j2=rest.indexOf(\"\\\\u0001\");return j2<0?{label:raw.slice(0,i),url:rest,logo:null}:{label:raw.slice(0,i),url:rest.slice(0,j2),logo:rest.slice(j2+1)}}function ac0($){if(!$)return TV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:TV1;return[...TV1,...$.verbs]}function L30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=t2(()=>{${_MARKER}.clear();return ac0(X).map((raw)=>{let p=_kiliParseLink(raw);if(p){${_MARKER}.set(p.label,{url:p.url,logo:p.logo});return p.label}return raw})},[X]),Z=t2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Ki(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%R30.length)},120);return()=>clearInterval(W)},[]),sk(()=>{U(Ki(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(!Q.includes(H))H=Q[0];if(Y===\"compacting\")H=\"Compacting\";let B=H+\"...\",K=${_MARKER}.get(H);_kiliLog({labels:Q,width:Z,drawn:H,wasStale:!Q.includes(z),linked:!!K,hasLogo:!!(K&&K.logo)});return E(\"div\",{className:Fi.container,style:{overflow:\"visible\",maxWidth:\"none\",width:\"auto\",flexWrap:\"nowrap\"},\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Fi.icon,style:{fontSize:\\`\\${$}px\\`},children:R30[G]}),K?j(\"a\",{ref:(el)=>{if(!el)return;try{var sel=[],q=el.parentElement;for(var i=0;i<8&&q;i++){var qr=q.getBoundingClientRect();if(qr.height>80)break;var cn=(typeof q.className===\"string\"?q.className:\"\").trim();if(cn)sel.push(\".\"+cn.split(/\\\\s+/).join(\".\"));q=q.parentElement}if(sel.length){var id=\"__kiliUnclip\",st=document.getElementById(id);if(!st){st=document.createElement(\"style\");st.id=id;document.head.appendChild(st)}var css=sel.join(\",\")+\"{overflow:visible!important;max-width:none!important;min-width:0!important;flex-shrink:0!important;text-overflow:clip!important;white-space:nowrap!important;animation:none!important;transition:none!important}\";if(st.textContent!==css)st.textContent=css}setTimeout(function(){try{var o=[],n=el;for(var k=0;k<8&&n;k++){var c=getComputedStyle(n),r=n.getBoundingClientRect();o.push(k+\":\"+n.tagName+\" w=\"+Math.round(r.width)+\" h=\"+Math.round(r.height)+\" sw=\"+n.scrollWidth+\" tlen=\"+((n.textContent||\"\").length)+\" anim=\"+c.animationName+\" ovf=\"+c.overflow);n=n.parentElement}var g=o.join(\" | \");if(g!==__kiliLastGeom){__kiliLastGeom=g;console.log(\"[kili-geom]\",g)}}catch(e){}},50)}catch(e){}},\"aria-hidden\":\"true\",className:Fi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},href:K.url,target:\"_blank\",rel:\"noopener noreferrer\",children:[K.logo?j(\"img\",{src:K.logo,alt:\"\",style:{width:\"14px\",height:\"14px\",borderRadius:\"3px\",objectFit:\"cover\",verticalAlign:\"middle\",marginRight:\"4px\"}}):null,B]}):j(\"span\",{\"aria-hidden\":\"true\",className:Fi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},children:B}),j(\"span\",{className:aO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}`,\n\t},\n\t{\n\t\tversion: \"2.1.250\",\n\t\tfind: 'function cc0($){if(!$)return NV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:NV1;return[...NV1,...$.verbs]}function R30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=o2(()=>cc0(X),[X]),Z=o2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Ki(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%w30.length)},120);return()=>clearInterval(W)},[]),rk(()=>{U(Ki(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(Y===\"compacting\")H=\"Compacting\";let B=lc0(H+\"...\",Z+3);return E(\"div\",{className:Fi.container,\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Fi.icon,style:{fontSize:`${$}px`},children:w30[G]}),j(\"span\",{\"aria-hidden\":\"true\",className:Fi.text,children:B}),j(\"span\",{className:dO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}',\n\t\treplace: `var ${_MARKER}=new Map();var __kiliLastLog=\"\";var __kiliLastGeom=\"\";function _kiliLog(o){try{var s=JSON.stringify(o);if(s===__kiliLastLog)return;__kiliLastLog=s;console.log(\"[kili]\",o)}catch(e){}}function _kiliParseLink(raw){let i=raw.indexOf(\"\\\\u0001\");if(i<0)return null;let rest=raw.slice(i+1);let j2=rest.indexOf(\"\\\\u0001\");return j2<0?{label:raw.slice(0,i),url:rest,logo:null}:{label:raw.slice(0,i),url:rest.slice(0,j2),logo:rest.slice(j2+1)}}function cc0($){if(!$)return NV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:NV1;return[...NV1,...$.verbs]}function R30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=o2(()=>{${_MARKER}.clear();return cc0(X).map((raw)=>{let p=_kiliParseLink(raw);if(p){${_MARKER}.set(p.label,{url:p.url,logo:p.logo});return p.label}return raw})},[X]),Z=o2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Ki(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%w30.length)},120);return()=>clearInterval(W)},[]),rk(()=>{U(Ki(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(!Q.includes(H))H=Q[0];if(Y===\"compacting\")H=\"Compacting\";let B=H+\"...\",K=${_MARKER}.get(H);_kiliLog({labels:Q,width:Z,drawn:H,wasStale:!Q.includes(z),linked:!!K,hasLogo:!!(K&&K.logo)});return E(\"div\",{className:Fi.container,style:{overflow:\"visible\",maxWidth:\"none\",width:\"auto\",flexWrap:\"nowrap\"},\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Fi.icon,style:{fontSize:\\`\\${$}px\\`},children:w30[G]}),K?j(\"a\",{ref:(el)=>{if(!el)return;try{var sel=[],q=el.parentElement;for(var i=0;i<8&&q;i++){var qr=q.getBoundingClientRect();if(qr.height>80)break;var cn=(typeof q.className===\"string\"?q.className:\"\").trim();if(cn)sel.push(\".\"+cn.split(/\\\\s+/).join(\".\"));q=q.parentElement}if(sel.length){var id=\"__kiliUnclip\",st=document.getElementById(id);if(!st){st=document.createElement(\"style\");st.id=id;document.head.appendChild(st)}var css=sel.join(\",\")+\"{overflow:visible!important;max-width:none!important;min-width:0!important;flex-shrink:0!important;text-overflow:clip!important;white-space:nowrap!important;animation:none!important;transition:none!important}\";if(st.textContent!==css)st.textContent=css}setTimeout(function(){try{var o=[],n=el;for(var k=0;k<8&&n;k++){var c=getComputedStyle(n),r=n.getBoundingClientRect();o.push(k+\":\"+n.tagName+\" w=\"+Math.round(r.width)+\" h=\"+Math.round(r.height)+\" sw=\"+n.scrollWidth+\" tlen=\"+((n.textContent||\"\").length)+\" anim=\"+c.animationName+\" ovf=\"+c.overflow);n=n.parentElement}var g=o.join(\" | \");if(g!==__kiliLastGeom){__kiliLastGeom=g;console.log(\"[kili-geom]\",g)}}catch(e){}},50)}catch(e){}},\"aria-hidden\":\"true\",className:Fi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},href:K.url,target:\"_blank\",rel:\"noopener noreferrer\",children:[K.logo?j(\"img\",{src:K.logo,alt:\"\",style:{width:\"14px\",height:\"14px\",borderRadius:\"3px\",objectFit:\"cover\",verticalAlign:\"middle\",marginRight:\"4px\"}}):null,B]}):j(\"span\",{\"aria-hidden\":\"true\",className:Fi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},children:B}),j(\"span\",{className:dO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}`,\n\t},\n\t{\n\t\tversion: \"2.1.247\",\n\t\tfind: 'function Ec0($){if(!$)return RV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:RV1;return[...RV1,...$.verbs]}function w30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=o2(()=>Ec0(X),[X]),Z=o2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Fi(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%M30.length)},120);return()=>clearInterval(W)},[]),rk(()=>{U(Fi(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(Y===\"compacting\")H=\"Compacting\";let B=Ic0(H+\"...\",Z+3);return E(\"div\",{className:Wi.container,\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Wi.icon,style:{fontSize:`${$}px`},children:M30[G]}),j(\"span\",{\"aria-hidden\":\"true\",className:Wi.text,children:B}),j(\"span\",{className:dO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}',\n\t\treplace: `var ${_MARKER}=new Map();var __kiliLastLog=\"\";var __kiliLastGeom=\"\";function _kiliLog(o){try{var s=JSON.stringify(o);if(s===__kiliLastLog)return;__kiliLastLog=s;console.log(\"[kili]\",o)}catch(e){}}function _kiliParseLink(raw){let i=raw.indexOf(\"\\\\u0001\");if(i<0)return null;let rest=raw.slice(i+1);let j2=rest.indexOf(\"\\\\u0001\");return j2<0?{label:raw.slice(0,i),url:rest,logo:null}:{label:raw.slice(0,i),url:rest.slice(0,j2),logo:rest.slice(j2+1)}}function Ec0($){if(!$)return RV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:RV1;return[...RV1,...$.verbs]}function w30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=o2(()=>{${_MARKER}.clear();return Ec0(X).map((raw)=>{let p=_kiliParseLink(raw);if(p){${_MARKER}.set(p.label,{url:p.url,logo:p.logo});return p.label}return raw})},[X]),Z=o2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Fi(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%M30.length)},120);return()=>clearInterval(W)},[]),rk(()=>{U(Fi(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(!Q.includes(H))H=Q[0];if(Y===\"compacting\")H=\"Compacting\";let B=H+\"...\",K=${_MARKER}.get(H);_kiliLog({labels:Q,width:Z,drawn:H,wasStale:!Q.includes(z),linked:!!K,hasLogo:!!(K&&K.logo)});return E(\"div\",{className:Wi.container,style:{overflow:\"visible\",maxWidth:\"none\",width:\"auto\",flexWrap:\"nowrap\"},\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Wi.icon,style:{fontSize:\\`\\${$}px\\`},children:M30[G]}),K?j(\"a\",{ref:(el)=>{if(!el)return;try{var sel=[],q=el.parentElement;for(var i=0;i<8&&q;i++){var qr=q.getBoundingClientRect();if(qr.height>80)break;var cn=(typeof q.className===\"string\"?q.className:\"\").trim();if(cn)sel.push(\".\"+cn.split(/\\\\s+/).join(\".\"));q=q.parentElement}if(sel.length){var id=\"__kiliUnclip\",st=document.getElementById(id);if(!st){st=document.createElement(\"style\");st.id=id;document.head.appendChild(st)}var css=sel.join(\",\")+\"{overflow:visible!important;max-width:none!important;min-width:0!important;flex-shrink:0!important;text-overflow:clip!important;white-space:nowrap!important;animation:none!important;transition:none!important}\";if(st.textContent!==css)st.textContent=css}setTimeout(function(){try{var o=[],n=el;for(var k=0;k<8&&n;k++){var c=getComputedStyle(n),r=n.getBoundingClientRect();o.push(k+\":\"+n.tagName+\" w=\"+Math.round(r.width)+\" h=\"+Math.round(r.height)+\" sw=\"+n.scrollWidth+\" tlen=\"+((n.textContent||\"\").length)+\" anim=\"+c.animationName+\" ovf=\"+c.overflow);n=n.parentElement}var g=o.join(\" | \");if(g!==__kiliLastGeom){__kiliLastGeom=g;console.log(\"[kili-geom]\",g)}}catch(e){}},50)}catch(e){}},\"aria-hidden\":\"true\",className:Wi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},href:K.url,target:\"_blank\",rel:\"noopener noreferrer\",children:[K.logo?j(\"img\",{src:K.logo,alt:\"\",style:{width:\"14px\",height:\"14px\",borderRadius:\"3px\",objectFit:\"cover\",verticalAlign:\"middle\",marginRight:\"4px\"}}):null,B]}):j(\"span\",{\"aria-hidden\":\"true\",className:Wi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},children:B}),j(\"span\",{className:dO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}`,\n\t},\n\t{\n\t\tversion: \"2.1.246\",\n\t\tfind: 'function Tc0($){if(!$)return RV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:RV1;return[...RV1,...$.verbs]}function _30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=i2(()=>Tc0(X),[X]),Z=i2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Fi(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%P30.length)},120);return()=>clearInterval(W)},[]),rk(()=>{U(Fi(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(Y===\"compacting\")H=\"Compacting\";let B=Ec0(H+\"...\",Z+3);return E(\"div\",{className:Wi.container,\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Wi.icon,style:{fontSize:`${$}px`},children:P30[G]}),j(\"span\",{\"aria-hidden\":\"true\",className:Wi.text,children:B}),j(\"span\",{className:dO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}',\n\t\treplace: `var ${_MARKER}=new Map();var __kiliLastLog=\"\";var __kiliLastGeom=\"\";function _kiliLog(o){try{var s=JSON.stringify(o);if(s===__kiliLastLog)return;__kiliLastLog=s;console.log(\"[kili]\",o)}catch(e){}}function _kiliParseLink(raw){let i=raw.indexOf(\"\\\\u0001\");if(i<0)return null;let rest=raw.slice(i+1);let j2=rest.indexOf(\"\\\\u0001\");return j2<0?{label:raw.slice(0,i),url:rest,logo:null}:{label:raw.slice(0,i),url:rest.slice(0,j2),logo:rest.slice(j2+1)}}function Tc0($){if(!$)return RV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:RV1;return[...RV1,...$.verbs]}function _30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=i2(()=>{${_MARKER}.clear();return Tc0(X).map((raw)=>{let p=_kiliParseLink(raw);if(p){${_MARKER}.set(p.label,{url:p.url,logo:p.logo});return p.label}return raw})},[X]),Z=i2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Fi(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%P30.length)},120);return()=>clearInterval(W)},[]),rk(()=>{U(Fi(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(!Q.includes(H))H=Q[0];if(Y===\"compacting\")H=\"Compacting\";let B=H+\"...\",K=${_MARKER}.get(H);_kiliLog({labels:Q,width:Z,drawn:H,wasStale:!Q.includes(z),linked:!!K,hasLogo:!!(K&&K.logo)});return E(\"div\",{className:Wi.container,style:{overflow:\"visible\",maxWidth:\"none\",width:\"auto\",flexWrap:\"nowrap\"},\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Wi.icon,style:{fontSize:\\`\\${$}px\\`},children:P30[G]}),K?j(\"a\",{ref:(el)=>{if(!el)return;try{var sel=[],q=el.parentElement;for(var i=0;i<8&&q;i++){var qr=q.getBoundingClientRect();if(qr.height>80)break;var cn=(typeof q.className===\"string\"?q.className:\"\").trim();if(cn)sel.push(\".\"+cn.split(/\\\\s+/).join(\".\"));q=q.parentElement}if(sel.length){var id=\"__kiliUnclip\",st=document.getElementById(id);if(!st){st=document.createElement(\"style\");st.id=id;document.head.appendChild(st)}var css=sel.join(\",\")+\"{overflow:visible!important;max-width:none!important;min-width:0!important;flex-shrink:0!important;text-overflow:clip!important;white-space:nowrap!important;animation:none!important;transition:none!important}\";if(st.textContent!==css)st.textContent=css}setTimeout(function(){try{var o=[],n=el;for(var k=0;k<8&&n;k++){var c=getComputedStyle(n),r=n.getBoundingClientRect();o.push(k+\":\"+n.tagName+\" w=\"+Math.round(r.width)+\" h=\"+Math.round(r.height)+\" sw=\"+n.scrollWidth+\" tlen=\"+((n.textContent||\"\").length)+\" anim=\"+c.animationName+\" ovf=\"+c.overflow);n=n.parentElement}var g=o.join(\" | \");if(g!==__kiliLastGeom){__kiliLastGeom=g;console.log(\"[kili-geom]\",g)}}catch(e){}},50)}catch(e){}},\"aria-hidden\":\"true\",className:Wi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},href:K.url,target:\"_blank\",rel:\"noopener noreferrer\",children:[K.logo?j(\"img\",{src:K.logo,alt:\"\",style:{width:\"14px\",height:\"14px\",borderRadius:\"3px\",objectFit:\"cover\",verticalAlign:\"middle\",marginRight:\"4px\"}}):null,B]}):j(\"span\",{\"aria-hidden\":\"true\",className:Wi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},children:B}),j(\"span\",{className:dO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}`,\n\t},\n\t{\n\t\tversion: \"2.1.245\",\n\t\tfind: 'function Lc0($){if(!$)return wV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:wV1;return[...wV1,...$.verbs]}function M30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=i2(()=>Lc0(X),[X]),Z=i2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Bi(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%j30.length)},120);return()=>clearInterval(W)},[]),dk(()=>{U(Bi(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(Y===\"compacting\")H=\"Compacting\";let B=Tc0(H+\"...\",Z+3);return E(\"div\",{className:Hi.container,\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Hi.icon,style:{fontSize:`${$}px`},children:j30[G]}),j(\"span\",{\"aria-hidden\":\"true\",className:Hi.text,children:B}),j(\"span\",{className:lO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}',\n\t\treplace: `var ${_MARKER}=new Map();var __kiliLastLog=\"\";var __kiliLastGeom=\"\";function _kiliLog(o){try{var s=JSON.stringify(o);if(s===__kiliLastLog)return;__kiliLastLog=s;console.log(\"[kili]\",o)}catch(e){}}function _kiliParseLink(raw){let i=raw.indexOf(\"\\\\u0001\");if(i<0)return null;let rest=raw.slice(i+1);let j2=rest.indexOf(\"\\\\u0001\");return j2<0?{label:raw.slice(0,i),url:rest,logo:null}:{label:raw.slice(0,i),url:rest.slice(0,j2),logo:rest.slice(j2+1)}}function Lc0($){if(!$)return wV1;if($.mode===\"replace\")return $.verbs.length>0?$.verbs:wV1;return[...wV1,...$.verbs]}function M30({size:$=16,permissionMode:J,status:Y,spinnerVerbsConfig:X}){let Q=i2(()=>{${_MARKER}.clear();return Lc0(X).map((raw)=>{let p=_kiliParseLink(raw);if(p){${_MARKER}.set(p.label,{url:p.url,logo:p.logo});return p.label}return raw})},[X]),Z=i2(()=>Math.max(...Q.map((W)=>W.length)),[Q]),[G,q]=Y1(0),[z,U]=Y1(()=>Bi(Q));Z1(()=>{let W=setInterval(()=>{q((F)=>(F+1)%j30.length)},120);return()=>clearInterval(W)},[]),dk(()=>{U(Bi(Q))},(W)=>{let F=[2000,3000,5000];return W<F.length?F[W]:5000});let H=z;if(!Q.includes(H))H=Q[0];if(Y===\"compacting\")H=\"Compacting\";let B=H+\"...\",K=${_MARKER}.get(H);_kiliLog({labels:Q,width:Z,drawn:H,wasStale:!Q.includes(z),linked:!!K,hasLogo:!!(K&&K.logo)});return E(\"div\",{className:Hi.container,style:{overflow:\"visible\",maxWidth:\"none\",width:\"auto\",flexWrap:\"nowrap\"},\"data-permission-mode\":J,children:[j(\"span\",{\"aria-hidden\":\"true\",className:Hi.icon,style:{fontSize:\\`\\${$}px\\`},children:j30[G]}),K?j(\"a\",{ref:(el)=>{if(!el)return;try{var sel=[],q=el.parentElement;for(var i=0;i<8&&q;i++){var qr=q.getBoundingClientRect();if(qr.height>80)break;var cn=(typeof q.className===\"string\"?q.className:\"\").trim();if(cn)sel.push(\".\"+cn.split(/\\\\s+/).join(\".\"));q=q.parentElement}if(sel.length){var id=\"__kiliUnclip\",st=document.getElementById(id);if(!st){st=document.createElement(\"style\");st.id=id;document.head.appendChild(st)}var css=sel.join(\",\")+\"{overflow:visible!important;max-width:none!important;min-width:0!important;flex-shrink:0!important;text-overflow:clip!important;white-space:nowrap!important;animation:none!important;transition:none!important}\";if(st.textContent!==css)st.textContent=css}setTimeout(function(){try{var o=[],n=el;for(var k=0;k<8&&n;k++){var c=getComputedStyle(n),r=n.getBoundingClientRect();o.push(k+\":\"+n.tagName+\" w=\"+Math.round(r.width)+\" h=\"+Math.round(r.height)+\" sw=\"+n.scrollWidth+\" tlen=\"+((n.textContent||\"\").length)+\" anim=\"+c.animationName+\" ovf=\"+c.overflow);n=n.parentElement}var g=o.join(\" | \");if(g!==__kiliLastGeom){__kiliLastGeom=g;console.log(\"[kili-geom]\",g)}}catch(e){}},50)}catch(e){}},\"aria-hidden\":\"true\",className:Hi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},href:K.url,target:\"_blank\",rel:\"noopener noreferrer\",children:[K.logo?j(\"img\",{src:K.logo,alt:\"\",style:{width:\"14px\",height:\"14px\",borderRadius:\"3px\",objectFit:\"cover\",verticalAlign:\"middle\",marginRight:\"4px\"}}):null,B]}):j(\"span\",{\"aria-hidden\":\"true\",className:Hi.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},children:B}),j(\"span\",{className:lO.visuallyHidden,children:Y===\"compacting\"?\"Compacting conversation\":\"Claude is working\"})]})}`,\n\t},\n\t{\n\t\tversion: \"2.1.232\",\n\t\tfind: 'function cBt(e){if(!e)return r0e;if(e.mode===\"replace\")return e.verbs.length>0?e.verbs:r0e;return[...r0e,...e.verbs]}function Mot({size:e=16,permissionMode:t,status:i,spinnerVerbsConfig:n}){let o=Jn(()=>cBt(n),[n]),r=Jn(()=>Math.max(...o.map((p)=>p.length)),[o]),[s,a]=ne(0),[l,c]=ne(()=>LG(o));se(()=>{let p=setInterval(()=>{a((f)=>(f+1)%Rot.length)},120);return()=>clearInterval(p)},[]),o0e(()=>{c(LG(o))},(p)=>{let f=[2000,3000,5000];return p<f.length?f[p]:5000});let u=l;if(i===\"compacting\")u=\"Compacting\";let h=dBt(u+\"...\",r+3);return I(\"div\",{className:kG.container,\"data-permission-mode\":t,children:[b(\"span\",{className:kG.icon,style:{fontSize:`${e}px`},children:Rot[s]}),b(\"span\",{className:kG.text,children:h})]})}',\n\t\treplace: `var ${_MARKER}=new Map();var __kiliLastLog=\"\";var __kiliLastGeom=\"\";function _kiliLog(o){try{var s=JSON.stringify(o);if(s===__kiliLastLog)return;__kiliLastLog=s;console.log(\"[kili]\",o)}catch(e){}}function _kiliParseLink(raw){let i=raw.indexOf(\"\\\\u0001\");if(i<0)return null;let rest=raw.slice(i+1);let j2=rest.indexOf(\"\\\\u0001\");return j2<0?{label:raw.slice(0,i),url:rest,logo:null}:{label:raw.slice(0,i),url:rest.slice(0,j2),logo:rest.slice(j2+1)}}function cBt(e){if(!e)return r0e;if(e.mode===\"replace\")return e.verbs.length>0?e.verbs:r0e;return[...r0e,...e.verbs]}function Mot({size:e=16,permissionMode:t,status:i,spinnerVerbsConfig:n}){let o=Jn(()=>{${_MARKER}.clear();return cBt(n).map((raw)=>{let p=_kiliParseLink(raw);if(p){${_MARKER}.set(p.label,{url:p.url,logo:p.logo});return p.label}return raw})},[n]),r=Jn(()=>Math.max(...o.map((p)=>p.length)),[o]),[s,a]=ne(0),[l,c]=ne(()=>LG(o));se(()=>{let p=setInterval(()=>{a((f)=>(f+1)%Rot.length)},120);return()=>clearInterval(p)},[]),o0e(()=>{c(LG(o))},(p)=>{let f=[2000,3000,5000];return p<f.length?f[p]:5000});let u=l;if(!o.includes(u))u=o[0];if(i===\"compacting\")u=\"Compacting\";let h=u+\"...\",K=${_MARKER}.get(u);_kiliLog({labels:o,width:r,drawn:u,wasStale:!o.includes(l),linked:!!K,hasLogo:!!(K&&K.logo)});return I(\"div\",{className:kG.container,style:{overflow:\"visible\",maxWidth:\"none\",width:\"auto\",flexWrap:\"nowrap\"},\"data-permission-mode\":t,children:[b(\"span\",{className:kG.icon,style:{fontSize:\\`\\${e}px\\`},children:Rot[s]}),K?b(\"a\",{ref:(el)=>{if(!el)return;try{var sel=[],q=el.parentElement;for(var i=0;i<8&&q;i++){var qr=q.getBoundingClientRect();if(qr.height>80)break;var cn=(typeof q.className===\"string\"?q.className:\"\").trim();if(cn)sel.push(\".\"+cn.split(/\\\\s+/).join(\".\"));q=q.parentElement}if(sel.length){var id=\"__kiliUnclip\",st=document.getElementById(id);if(!st){st=document.createElement(\"style\");st.id=id;document.head.appendChild(st)}var css=sel.join(\",\")+\"{overflow:visible!important;max-width:none!important;min-width:0!important;flex-shrink:0!important;text-overflow:clip!important;white-space:nowrap!important;animation:none!important;transition:none!important}\";if(st.textContent!==css)st.textContent=css}setTimeout(function(){try{var o=[],n=el;for(var k=0;k<8&&n;k++){var c=getComputedStyle(n),r=n.getBoundingClientRect();o.push(k+\":\"+n.tagName+\" w=\"+Math.round(r.width)+\" h=\"+Math.round(r.height)+\" sw=\"+n.scrollWidth+\" tlen=\"+((n.textContent||\"\").length)+\" anim=\"+c.animationName+\" ovf=\"+c.overflow);n=n.parentElement}var g=o.join(\" | \");if(g!==__kiliLastGeom){__kiliLastGeom=g;console.log(\"[kili-geom]\",g)}}catch(e){}},50)}catch(e){}},className:kG.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},href:K.url,target:\"_blank\",rel:\"noopener noreferrer\",children:[K.logo?b(\"img\",{src:K.logo,alt:\"\",style:{width:\"14px\",height:\"14px\",borderRadius:\"3px\",objectFit:\"cover\",verticalAlign:\"middle\",marginRight:\"4px\"}}):null,h]}):b(\"span\",{className:kG.text,style:{color:\"#22c55e\",whiteSpace:\"nowrap\",overflow:\"visible\",textOverflow:\"clip\",maxWidth:\"none\",flexShrink:0,width:\"auto\",animation:\"none\",transition:\"none\"},children:h})]})}`,\n\t},\n];\n\nexport type TPatchResult = \"patched\" | \"already-patched\" | \"no-match\" | \"error\";\n\n// Built via fromCharCode, not a literal byte in source -- this file has\n// previously been bitten by literal control bytes landing silently in\n// source text instead of an escape sequence (see copy.ts). SOH (0x01) can\n// never appear in real ad copy, so it needs no further escaping.\nconst _LINK_SEP = String.fromCharCode(1);\n\n/** Encodes a clickable, optionally logo'd spinner verb for `_kiliParseLink`\n * (see `_ANCHORS` above) to split back into a label, a url, and an optional\n * logo image url. The logo segment is only appended when present, so a\n * two-segment encoding (no logo) still round-trips through the same parser\n * unchanged. */\nexport function encodeLinkedVerb(\n\tlabel: string,\n\turl: string,\n\tlogoUrl?: string,\n): string {\n\treturn logoUrl\n\t\t? `${label}${_LINK_SEP}${url}${_LINK_SEP}${logoUrl}`\n\t\t: `${label}${_LINK_SEP}${url}`;\n}\n\n/**\n * Re-patching an already-patched bundle: the fix cannot be applied on top of\n * itself (the `find` anchor is the ORIGINAL shipped code, which the patched\n * file no longer contains), so a bundle carrying an older patch has to be\n * restored from its `.kili-orig` backup first and then patched fresh.\n *\n * Without this, `patchFile` returned `\"already-patched\"` for any file bearing\n * the marker and stopped -- meaning every future fix to the injected code\n * (the stale-verb clamp, the width guard, the layout styles, this logging)\n * would ship in the extension, be reported as installed, and silently never\n * reach the running webview of anyone who was already patched. That is\n * exactly the class of \"the fix is published but nothing changed\" loop that\n * makes this component so expensive to debug, so the version is embedded in\n * the file itself rather than tracked in config: the bundle states which\n * patch it is carrying, and disagreement is self-correcting.\n */\nconst _PATCH_VERSION = \"9\";\nconst _VERSION_TAG = `${_MARKER}_v${_PATCH_VERSION}`;\n/** Exported for tests only -- lets `editorSettings.test.ts` fabricate an\n * already-patched webview file without duplicating a real minified anchor\n * string just to exercise `isCurrentlyPatched()`. */\nexport const TEST_ONLY_VERSION_TAG = _VERSION_TAG;\n\nexport function patchFile(filePath: string): TPatchResult {\n\ttry {\n\t\tif (!existsSync(filePath)) return \"error\";\n\t\tlet original = readFileSync(filePath, \"utf8\");\n\n\t\tif (original.includes(_VERSION_TAG)) return \"already-patched\";\n\n\t\t// Carries an OLDER patch: roll back to pristine so the anchor matches\n\t\t// again, then fall through and apply the current one.\n\t\tif (original.includes(_MARKER)) {\n\t\t\tconst backupPath = `${filePath}${_BACKUP_SUFFIX}`;\n\t\t\tif (!existsSync(backupPath)) return \"error\";\n\t\t\toriginal = readFileSync(backupPath, \"utf8\");\n\t\t\twriteFileSync(filePath, original, \"utf8\");\n\t\t}\n\n\t\tconst anchor = _ANCHORS.find((a) => original.includes(a.find));\n\t\tif (!anchor) return \"no-match\";\n\t\tconst patched = `/*${_VERSION_TAG}*/${original.replace(anchor.find, anchor.replace)}`;\n\t\tif (!existsSync(`${filePath}${_BACKUP_SUFFIX}`)) {\n\t\t\twriteFileSync(`${filePath}${_BACKUP_SUFFIX}`, original, \"utf8\");\n\t\t}\n\t\twriteFileSync(filePath, patched, \"utf8\");\n\t\treturn \"patched\";\n\t} catch {\n\t\treturn \"error\";\n\t}\n}\n\nexport function restoreFile(filePath: string): boolean {\n\tconst backupPath = `${filePath}${_BACKUP_SUFFIX}`;\n\ttry {\n\t\tif (!existsSync(backupPath)) return false;\n\t\twriteFileSync(filePath, readFileSync(backupPath, \"utf8\"), \"utf8\");\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/** One installed Claude Code webview file, tagged with the same editor-folder\n * name `editorSettings.ts`'s `_userSettingsFolder` uses (\"Cursor\" / \"Code\" /\n * \"VSCodium\") -- this is what lets patch success be tracked per editor\n * instead of as one global flag. Different editors update Claude Code on\n * their own schedule, so it's normal for one to be on a build we have an\n * anchor for while another is on a newer one we don't -- see `_ANCHORS`'s\n * doc comment. */\nexport type TWebviewFile = { editorFolder: string; filePath: string };\n\n/** Parses the leading `X.Y.Z` out of an `anthropic.claude-code-<version>`\n * (or `...-<version>-<platform>-<arch>`) extension folder name. `null` for\n * anything that doesn't match, so callers can fall back to mtime. */\nfunction _parseVersion(folderName: string): [number, number, number] | null {\n\tconst m = folderName.match(/^anthropic\\.claude-code-(\\d+)\\.(\\d+)\\.(\\d+)/);\n\tif (!m) return null;\n\treturn [Number(m[1]), Number(m[2]), Number(m[3])];\n}\n\n/** Every installed Claude Code webview bundle across every editor on this\n * machine (Cursor, VS Code, VSCodium) -- there's no `vscode` API to ask\n * \"which editor is this,\" so, same as `editorSettings.ts`, this patches\n * whichever ones actually exist on disk.\n *\n * Exactly ONE file per editor, the newest installed version -- VS Code\n * usually removes an extension's old version folder the moment it updates,\n * but not always immediately (confirmed live: a machine with BOTH\n * `anthropic.claude-code-2.1.252-...` and a newer `...-2.1.258-...`\n * sitting side by side at once, the update not yet cleaned up). Returning\n * every matching folder used to mean an editor with an old, still-patched\n * leftover folder AND a newer, genuinely-unpatched one both got reported as\n * \"this editor is patched\" -- `isCurrentlyPatched`/`applyToAllInstalled`\n * only need the version that's actually loaded and rendering right now,\n * which is always the newest one, never an update's stale leftover.\n */\nexport function findClaudeCodeWebviewFiles(): TWebviewFile[] {\n\t// `~/.vscode`, `~/.cursor`, `~/.vscode-oss` -- unlike settings.json's\n\t// per-OS \"Application Support\" path, each editor's extensions folder\n\t// lives directly under the home directory on every platform, so\n\t// `homedir()` alone is enough. This used to key off `USERPROFILE`, a\n\t// Windows-only env var that is always `undefined` on macOS/Linux --\n\t// meaning this returned no files, the patch silently never ran, and\n\t// every non-Windows install fell back to plain unclickable text no\n\t// matter how well-supported its webview build was. Confirmed live: this\n\t// was breaking every macOS install until now.\n\tconst home = homedir();\n\tconst extensionRoots: Array<{ editorFolder: string; root: string }> = [\n\t\t{ editorFolder: \"Cursor\", root: join(home, \".cursor\", \"extensions\") },\n\t\t{ editorFolder: \"Code\", root: join(home, \".vscode\", \"extensions\") },\n\t\t{\n\t\t\teditorFolder: \"VSCodium\",\n\t\t\troot: join(home, \".vscode-oss\", \"extensions\"),\n\t\t},\n\t];\n\n\tconst found: TWebviewFile[] = [];\n\tfor (const { editorFolder, root } of extensionRoots) {\n\t\tif (!existsSync(root)) continue;\n\t\tlet entries: string[] = [];\n\t\ttry {\n\t\t\tentries = readdirSync(root);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\t// Candidates for THIS editor only -- version-compared against each\n\t\t// other below, never across editors.\n\t\tconst candidates: Array<{\n\t\t\tfilePath: string;\n\t\t\tversion: [number, number, number] | null;\n\t\t\tmtimeMs: number;\n\t\t}> = [];\n\t\tfor (const entry of entries) {\n\t\t\tif (!entry.startsWith(\"anthropic.claude-code-\")) continue;\n\t\t\tconst filePath = join(root, entry, \"webview\", \"index.js\");\n\t\t\tif (!existsSync(filePath)) continue;\n\t\t\tlet mtimeMs = 0;\n\t\t\ttry {\n\t\t\t\tmtimeMs = statSync(filePath).mtimeMs;\n\t\t\t} catch {\n\t\t\t\t/* fall through with mtimeMs 0 -- version comparison still applies */\n\t\t\t}\n\t\t\tcandidates.push({ filePath, version: _parseVersion(entry), mtimeMs });\n\t\t}\n\t\tif (candidates.length === 0) continue;\n\t\t// Highest parsed version wins; unparseable folder names (or a tie)\n\t\t// fall back to the newest mtime.\n\t\tconst newest = candidates.reduce((best, c) => {\n\t\t\tif (c.version && best.version) {\n\t\t\t\tfor (let i = 0; i < 3; i++) {\n\t\t\t\t\tif (c.version[i] !== best.version[i]) {\n\t\t\t\t\t\treturn c.version[i] > best.version[i] ? c : best;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn c.mtimeMs > best.mtimeMs ? c : best;\n\t\t\t}\n\t\t\tif (c.version && !best.version) return c;\n\t\t\tif (!c.version && best.version) return best;\n\t\t\treturn c.mtimeMs > best.mtimeMs ? c : best;\n\t\t});\n\t\tfound.push({ editorFolder, filePath: newest.filePath });\n\t}\n\treturn found;\n}\n\n/**\n * Live, on-disk answer to \"is this editor's Claude Code webview actually\n * patched RIGHT NOW\" -- reads the current file(s) fresh, never trusts a\n * cached flag. `~/.kili/config.json`'s `webviewPatchedEditors` is a snapshot\n * from whenever `_applyWebviewPatch()` last ran (extension activation, or a\n * `kili.*` config change) -- it goes stale the moment Claude Code\n * auto-updates itself in between: a version bump replaces\n * `anthropic.claude-code-<old>/webview/index.js` with a brand new,\n * unpatched `anthropic.claude-code-<new>/webview/index.js`, and nothing\n * re-runs the patch until this extension's host next activates or its\n * config changes -- which, for a long-running editor window, can be a long\n * time, or never before the next restart. In that window, the stale cache\n * still says \"patched\", so `editorSettings.ts` kept sending the\n * link-encoded verb to a webview that had already reverted to plain,\n * unpatched code -- rendering as visible raw `[label]\u0001url` garbage\n * text instead of a link. Confirmed live: exactly this happened after a\n * Claude Code auto-update with no editor reload in between.\n *\n * Cheap enough to call on every write (`hook.ts` runs fresh per turn\n * anyway, and this is a handful of file reads/`includes` checks), so\n * callers should prefer this over `webviewPatchedEditors` for the\n * link-vs-plain decision itself; `webviewPatchedEditors` remains useful for\n * `extension.ts`'s own \"did I just newly patch something, should I prompt a\n * reload\" transition-detection, which is a different question.\n */\nexport function isCurrentlyPatched(editorFolder: string): boolean {\n\treturn findClaudeCodeWebviewFiles()\n\t\t.filter((f) => f.editorFolder === editorFolder)\n\t\t.some((f) => {\n\t\t\ttry {\n\t\t\t\treturn readFileSync(f.filePath, \"utf8\").includes(_VERSION_TAG);\n\t\t\t} catch {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n}\n\nexport type TPatchSummary = {\n\tpatched: number;\n\tskipped: number;\n\tfailed: number;\n\t/** Editor-folder names (\"Cursor\"/\"Code\"/\"VSCodium\") whose webview is\n\t * actually patched right now -- the only editors it's safe to send a\n\t * link-encoded spinner verb to. An editor missing from this list must get\n\t * plain text, even if some *other* editor on the same machine patched\n\t * fine: each editor updates Claude Code independently, so patch success\n\t * is never all-or-nothing across a machine. */\n\tpatchedFolders: string[];\n};\n\nexport function applyToAllInstalled(): TPatchSummary {\n\tconst summary: TPatchSummary = {\n\t\tpatched: 0,\n\t\tskipped: 0,\n\t\tfailed: 0,\n\t\tpatchedFolders: [],\n\t};\n\tfor (const { editorFolder, filePath } of findClaudeCodeWebviewFiles()) {\n\t\tconst result = patchFile(filePath);\n\t\tif (result === \"patched\" || result === \"already-patched\") {\n\t\t\tsummary.patched++;\n\t\t\tif (!summary.patchedFolders.includes(editorFolder)) {\n\t\t\t\tsummary.patchedFolders.push(editorFolder);\n\t\t\t}\n\t\t} else if (result === \"no-match\") summary.skipped++;\n\t\telse summary.failed++;\n\t}\n\treturn summary;\n}\n\nexport function restoreAllInstalled(): number {\n\tlet restored = 0;\n\tfor (const { filePath } of findClaudeCodeWebviewFiles()) {\n\t\tif (restoreFile(filePath)) restored++;\n\t}\n\treturn restored;\n}\n","import type { TAd } from \"./types\";\nimport { encodeLinkedVerb } from \"./webviewPatch\";\n\n// Built via fromCharCode rather than escape-sequence literals in source:\n// this file has previously been bitten by literal ESC/BEL control bytes\n// silently landing in the source text instead of the intended two-character\n// escape sequences -- fromCharCode sidesteps that entirely.\nconst _ESC = String.fromCharCode(27);\nconst _DIM = `${_ESC}[2m`;\nconst _RESET = `${_ESC}[0m`;\n\n/** One-line ad copy shared by every surface -- \"brand: text\" if a brand name\n * is present, otherwise just the text. */\nexport function adLine(ad: TAd): string {\n\tconst text = ad.adText.trim();\n\treturn ad.brandName ? `${ad.brandName}: ${text}` : text;\n}\n\n/** The ad's own title when the server sent one -- shorter and more\n * recognizable than `adLine()`'s brand+body combo. Falls back to `adLine()`\n * for an ad with no `title` at all. */\nexport function adTitle(ad: TAd): string {\n\treturn ad.title?.trim() || adLine(ad);\n}\n\n/** \"name: body\" -- the ad's own title (not `brandName`) paired with its body\n * copy, what `spinnerVerb()` wraps in brackets. Falls back to the bare body\n * for an ad with no `title` at all, same fallback shape as `adTitle()`. */\nexport function adNameLine(ad: TAd): string {\n\tconst name = ad.title?.trim();\n\tconst body = ad.adText.trim();\n\treturn name ? `${name}: ${body}` : body;\n}\n\n/**\n * The spinner pads to `max(verbLength) + 3`, so one long verb widens the\n * whole spinner region. Keeps well under Claude Code's own longest built-in\n * verbs. Prefers a word boundary, but only backs off to one when doing so\n * doesn't waste more than a few characters of the budget -- otherwise a\n * short first word (e.g. \"Acme\") would truncate far short of the limit.\n */\nexport function truncate(text: string, maxLength: number): string {\n\tif (text.length <= maxLength) return text;\n\tconst hardCut = text.slice(0, maxLength - 1);\n\tconst lastSpace = hardCut.lastIndexOf(\" \");\n\tconst wastedByBackingOff = hardCut.length - lastSpace;\n\tconst cut =\n\t\tlastSpace > 0 && wastedByBackingOff <= 6\n\t\t\t? hardCut.slice(0, lastSpace)\n\t\t\t: hardCut;\n\treturn `${cut.trimEnd()}…`;\n}\n\n/**\n * Briefly dropped to 32 to \"fix\" clipped ad copy. That was wrong and is\n * reverted: the label length was never the problem. Claude Code sizes the\n * spinner region from `max(verbLength) + 3` -- the RAW verb string, which for\n * the extension's link-encoded form is label + SOH + tracking URL + SOH +\n * base64 logo. Measured live: 7,126 characters total, of which the label was\n * 26. Truncating the label shrinks 26 of 7,126 and changes nothing about the\n * broken layout; it just costs advertisers their copy. The real fix is\n * shrinking the *payload* (see `logoCache.ts`'s `_MAX_BYTES`).\n */\nconst _SPINNER_MAX = 60;\nconst _SPINNER_PREFIX = \"[\";\nconst _SPINNER_SUFFIX = \"]\";\n\n/**\n * What the spinner shows between \"a turn started\" and \"this turn's ad\n * resolved\". Deliberately an explicit value, never `undefined`/key-deletion:\n * removing `claudeCode.spinnerVerbs` from settings.json does NOT visibly\n * reset the panel -- Claude Code's webview keeps the last verbs it read in\n * memory and only re-renders on a *new* value, so a delete left the previous\n * turn's ad on screen for the entire fetch (confirmed live: 4.7s between\n * `hook.ts` clearing at turn start and the real ad landing, with the old ad\n * visible the whole time). Writing Claude's own style of verb explicitly is\n * what actually replaces it, and matches the request to fall back to\n * Claude's own thinking text rather than any \"Sponsored\"-branded placeholder.\n */\nexport const RESET_VERBS = [\"Thinking…\"];\n\n/**\n * \"[<name>: <body>]\" — reads unmistakably as an ad in place of\n * \"Discombobulating…\", and the brackets keep it visually distinct from\n * Claude's own status text either side of it. No \"KILI AD:\" label -- just\n * the ad's own name paired with its body copy (`adNameLine()`), the text an\n * advertiser actually wrote on the campaign form. Still truncates as a last\n * resort so the closing bracket is never cut off.\n *\n * Never clickable as plain text -- confirmed by reading the shipped webview\n * bundle: the verb string is normally rendered straight into a React\n * `<span>`'s `children`, with no markdown/link parsing anywhere in that\n * path. Use this for the CLI terminal spinner (a real TTY, no way around\n * it) and as the plain-text fallback for the extension spinner. For the\n * extension spinner specifically, prefer `spinnerVerbLink()` below --\n * `webviewPatch.ts` patches that one `<span>` to understand it.\n */\nexport function spinnerVerb(ad: TAd): string {\n\tconst budget = _SPINNER_MAX - _SPINNER_PREFIX.length - _SPINNER_SUFFIX.length;\n\tconst body = truncate(adNameLine(ad), Math.max(10, budget));\n\treturn `${_SPINNER_PREFIX}${body}${_SPINNER_SUFFIX}`;\n}\n\n/**\n * The extension spinner's clickable form -- same visible text as\n * `spinnerVerb()`, but encoded (via `encodeLinkedVerb`) for the patch\n * installed by `webviewPatch.ts` to unpack into a real `<a href>`.\n *\n * Only ever call this when the patch is confirmed applied\n * (`config.webviewPatched`). Without the patch, nothing understands the\n * encoding: the unmodified renderer just prints the whole raw string,\n * including the url, in plain view -- not a graceful degradation, an\n * actual regression back to the `[[label]](url)` mess this package shipped\n * once already. `refresh.ts` is what gates this; this function doesn't\n * check the flag itself, since it has no way to read it.\n *\n * `logoDataUri` overrides `ad.favicon` -- the chat panel webview's CSP\n * (`img-src 'self' https://*.vscode-cdn.net data:`, confirmed via its own\n * DevTools console) blocks loading `ad.favicon`'s raw remote URL entirely,\n * so `refresh.ts` resolves it to a cached `data:` URI (see `logoCache.ts`)\n * before calling this. Passing nothing here falls back to the raw URL,\n * which is only ever correct for a caller that doesn't need it to actually\n * render as an image (none currently do -- kept as a fallback, not a path\n * anything exercises).\n */\nexport function spinnerVerbLink(ad: TAd, logoDataUri?: string | null): string {\n\tconst verb = spinnerVerb(ad);\n\t// `undefined` (param omitted) means \"no resolution attempted, use\n\t// ad.favicon as-is\" -- `null` (param explicitly passed) means \"resolution\n\t// was attempted and came back empty, omit the logo entirely\" rather than\n\t// falling back to the raw URL that's the whole reason this override\n\t// exists. `??` would collapse those two cases together; this doesn't.\n\tconst logo =\n\t\tlogoDataUri === undefined ? ad.favicon : (logoDataUri ?? undefined);\n\treturn ad.clickUrl ? encodeLinkedVerb(verb, ad.clickUrl, logo) : verb;\n}\n\nexport function dim(text: string): string {\n\treturn `${_DIM}${text}${_RESET}`;\n}\n","import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { readJsonOwnedByUser, writeJsonAtomic } from \"./store\";\nimport { isCurrentlyPatched } from \"./webviewPatch\";\n\n/** Every editor identity this module knows how to locate. `hook.ts` (a\n * plain Node process with no `vscode` API, so no `vscode.env.appName` to\n * read) uses this to update whichever ones are actually installed, rather\n * than needing to know which editor is running Claude Code's chat panel. */\nconst _KNOWN_APP_NAMES = [\"Cursor\", \"Visual Studio Code\", \"VSCodium\"];\n\n/**\n * `vscode.workspace.getConfiguration(\"claudeCode\").update(...)` silently\n * no-ops for `spinnerVerbs`: it's not declared in any extension's\n * `contributes.configuration`, and VS Code's Configuration API only\n * reliably persists keys under a namespace some extension owns (ours works\n * fine for `kili.*`, which we do declare). So for this one undocumented,\n * cross-extension key, write the editor's own `settings.json` directly --\n * merge-only, same discipline as `claude/settings.ts` uses for\n * `~/.claude/settings.json`.\n */\n\nfunction _userSettingsFolder(appName: string): string | null {\n\tconst lower = appName.toLowerCase();\n\tif (lower.includes(\"cursor\")) return \"Cursor\";\n\tif (lower.includes(\"vscodium\")) return \"VSCodium\";\n\tif (lower.includes(\"visual studio code\") || lower.includes(\"code\"))\n\t\treturn \"Code\";\n\treturn null;\n}\n\nexport function editorSettingsPath(appName: string): string | null {\n\tconst folder = _userSettingsFolder(appName);\n\tif (!folder) return null;\n\tconst home = homedir();\n\tswitch (process.platform) {\n\t\tcase \"win32\": {\n\t\t\tconst appData = process.env.APPDATA ?? join(home, \"AppData\", \"Roaming\");\n\t\t\treturn join(appData, folder, \"User\", \"settings.json\");\n\t\t}\n\t\tcase \"darwin\":\n\t\t\treturn join(\n\t\t\t\thome,\n\t\t\t\t\"Library\",\n\t\t\t\t\"Application Support\",\n\t\t\t\tfolder,\n\t\t\t\t\"User\",\n\t\t\t\t\"settings.json\",\n\t\t\t);\n\t\tdefault:\n\t\t\treturn join(\n\t\t\t\tprocess.env.XDG_CONFIG_HOME ?? join(home, \".config\"),\n\t\t\t\tfolder,\n\t\t\t\t\"User\",\n\t\t\t\t\"settings.json\",\n\t\t\t);\n\t}\n}\n\n/**\n * Reads via `readJsonOwnedByUser`, not `readJson` -- this is the editor's own\n * `settings.json`, the file that also holds the user's theme, activity bar\n * layout, and everything else. VS Code accepts JSONC comments/trailing\n * commas there, which `JSON.parse` can't, and treating a parse failure as\n * \"empty\" here means a merge-write silently discards all of it, keeping only\n * `claudeCode.spinnerVerbs` -- confirmed: this happened for real, on a file\n * this function is called against on *every single turn* via `hook.ts`.\n * Throws `SettingsParseError` on a genuinely unparseable existing file;\n * callers must catch and skip, never let it silently wipe the file.\n */\nexport function writeClaudeCodeSpinnerVerbs(\n\tappName: string,\n\tverbs: string[] | undefined,\n): boolean {\n\tconst path = editorSettingsPath(appName);\n\tif (!path) return false;\n\tconst current = readJsonOwnedByUser<Record<string, unknown>>(path, {});\n\t// Same object shape as the CLI's `spinnerVerbs` in ~/.claude/settings.json\n\t// ({mode, verbs}), not a bare array -- Claude Code's webview does\n\t// `for (const v of value.verbs)` and crashes (\"e.verbs is not iterable\")\n\t// on a bare array, since `value.verbs` is then undefined. Confirmed the\n\t// hard way against a live Cursor install.\n\t//\n\t// JSON.stringify drops an undefined-valued key, so assigning `undefined`\n\t// here has the same on-disk effect as deleting it.\n\tconst next = {\n\t\t...current,\n\t\t\"claudeCode.spinnerVerbs\":\n\t\t\tverbs === undefined ? undefined : { mode: \"replace\", verbs },\n\t};\n\twriteJsonAtomic(path, next);\n\treturn true;\n}\n\n/**\n * Same write, but for every editor actually installed on this machine\n * (detected by its settings.json already existing) rather than one named\n * editor. `hook.ts` calls this on every `UserPromptSubmit` so the chat-panel\n * spinner refreshes per-turn, the same as the terminal spinner -- the\n * extension's own 60s timer alone left it looking stuck across turns inside\n * that window.\n *\n * Takes both a plain and a link-encoded verb rather than one pre-decided\n * value: which one is safe to send is a per-editor question, not a\n * machine-wide one. `patchedEditorFolders` names exactly the editors (by the\n * same \"Cursor\"/\"Code\"/\"VSCodium\" folder name `_userSettingsFolder` returns)\n * whose Claude Code webview is actually patched to decode the link encoding\n * -- every other editor gets the plain verb, even if some other editor on\n * this same machine patched fine. Sending the link form to an unpatched\n * editor doesn't degrade gracefully, it leaks the raw SOH-separated url as\n * visible garbage text (confirmed live, before this per-editor split\n * existed -- see `TPatchSummary.patchedFolders`'s doc comment).\n */\n/**\n * Clears `kili.apiKey` in every editor actually installed on this machine,\n * not just the one running this extension process right now -- `_handleSignOut`\n * in `extension.ts` still separately calls `vscode.workspace.getConfiguration\n * (\"kili\").update(\"apiKey\", \"\", Global)` for the *current* editor (so that\n * editor's own UI reacts live via `onDidChangeConfiguration`, which a direct\n * file write can't trigger), but that call is scoped to the editor process\n * this code happens to be running inside -- it has no way to reach a\n * *different* installed editor's settings.json. Without this, signing out\n * in Cursor left VS Code's own copy of the key untouched, and worse: VS\n * Code's next activation/config-sync would read that still-present key and\n * write it right back into the shared `~/.kili/config.json` cache, silently\n * undoing the sign-out. Confirmed live.\n *\n * Same merge-only, JSONC-safe discipline as\n * `writeClaudeCodeSpinnerVerbsEverywhereInstalled` -- one editor's\n * unparseable `settings.json` must not block clearing a different, valid\n * one.\n */\nexport function clearKiliApiKeyEverywhereInstalled(): void {\n\tfor (const appName of _KNOWN_APP_NAMES) {\n\t\tconst path = editorSettingsPath(appName);\n\t\tif (!path || !existsSync(path)) continue;\n\t\ttry {\n\t\t\tconst current = readJsonOwnedByUser<Record<string, unknown>>(path, {});\n\t\t\tif (!(\"kili.apiKey\" in current) || current[\"kili.apiKey\"] === \"\") {\n\t\t\t\tcontinue; // nothing to clear, avoid a no-op write/mtime bump\n\t\t\t}\n\t\t\twriteJsonAtomic(path, { ...current, \"kili.apiKey\": \"\" });\n\t\t} catch {\n\t\t\t// See writeClaudeCodeSpinnerVerbs's doc comment: an unparseable\n\t\t\t// settings.json for one editor must not block clearing another.\n\t\t}\n\t}\n}\n\n/**\n * No `patchedEditorFolders` parameter -- deliberately dropped in favor of\n * `webviewPatch.ts`'s `isCurrentlyPatched()`, a live, on-disk check, not a\n * cached flag from whenever this extension last activated. A cached list\n * goes stale the moment Claude Code auto-updates itself in between\n * activations (a version bump ships a brand new, unpatched webview bundle\n * under a new `anthropic.claude-code-<version>` folder) -- this used to keep\n * sending the link-encoded verb to an editor the cache still believed was\n * patched, which rendered as visible raw `[label]url` garbage text instead\n * of a link. Confirmed live.\n */\nexport function writeClaudeCodeSpinnerVerbsEverywhereInstalled(\n\tplainVerbs: string[] | undefined,\n\tlinkVerbs: string[] | undefined,\n): void {\n\tfor (const appName of _KNOWN_APP_NAMES) {\n\t\tconst path = editorSettingsPath(appName);\n\t\tif (!path || !existsSync(path)) continue;\n\t\tconst folder = _userSettingsFolder(appName);\n\t\tconst isPatched = folder !== null && isCurrentlyPatched(folder);\n\t\ttry {\n\t\t\twriteClaudeCodeSpinnerVerbs(appName, isPatched ? linkVerbs : plainVerbs);\n\t\t} catch {\n\t\t\t// One editor's unparseable settings.json must not block updating a\n\t\t\t// different, valid one -- see writeClaudeCodeSpinnerVerbs's doc comment.\n\t\t}\n\t}\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { claudeSettingsPath, settingsBackupPath } from \"../core/paths\";\nimport { readJson, readJsonOwnedByUser, writeJsonAtomic } from \"../core/store\";\n\n/**\n * Exactly the top-level keys `enable`/`disable` are allowed to touch in\n * `~/.claude/settings.json` -- a shared, user-owned file that may already\n * hold `mcpServers` and other config we must never rewrite wholesale.\n */\nconst OWNED_KEYS = [\n\t\"spinnerVerbs\",\n\t\"spinnerTipsOverride\",\n\t\"statusLine\",\n] as const;\n\n/** Our two hook entries, matched by this marker inside each command string\n * so `disable()` can remove precisely the ones we added even if the user's\n * `hooks` block also has entries of their own for the same events. */\nconst _HOOK_MARKER = \"__kili_hook__\";\nconst OWNED_HOOK_EVENTS = [\"UserPromptSubmit\", \"Stop\"] as const;\n\nexport type TClaudeSettings = Record<string, unknown> & {\n\thooks?: Record<string, unknown[]>;\n};\n\n/**\n * Copies the file byte-for-byte, not parse-then-restringify -- a backup's\n * whole job is to be restorable later, so it must work even when the file\n * has JSONC comments `JSON.parse` can't handle (round-tripping through\n * `JSON.stringify` would silently drop them from the backup too). No-ops if\n * the file doesn't exist yet -- nothing to back up.\n */\nexport function backupOnce(): void {\n\tconst backupPath = settingsBackupPath();\n\tif (existsSync(backupPath)) return;\n\tconst settingsPath = claudeSettingsPath();\n\tif (!existsSync(settingsPath)) return;\n\tmkdirSync(dirname(backupPath), { recursive: true });\n\twriteFileSync(backupPath, readFileSync(settingsPath, \"utf8\"), \"utf8\");\n}\n\n/**\n * All three of `enable`/`updateSpinnerVerb`/`disable` read via\n * `readJsonOwnedByUser`, not `readJson` -- this file is the user's own,\n * commonly hand-edited with JSONC comments `JSON.parse` can't handle. Letting\n * a parse failure fall through to `writeJsonAtomic` as if the file were empty\n * would silently discard everything else in it (confirmed: this happened for\n * real). Callers (`extension.ts`) must catch `SettingsParseError` and warn\n * instead of writing, not let it crash outright.\n */\nexport function enable(hookBinPath: string): void {\n\tbackupOnce();\n\tconst settings = readJsonOwnedByUser<TClaudeSettings>(\n\t\tclaudeSettingsPath(),\n\t\t{},\n\t);\n\n\tsettings.spinnerVerbs = { mode: \"replace\", verbs: [\"Sponsored\"] };\n\t// `statusLine` is still configured -- `statusline.js` running at all\n\t// (regardless of what it prints) is `isTerminalActive`'s only signal that\n\t// a real terminal, not the IDE chat panel, is currently in front of the\n\t// user; removing this entirely would silently break that and misattribute\n\t// every terminal turn's impression to the extension surface instead. What\n\t// it prints changed instead -- see `statusline.ts`: it no longer renders\n\t// the ad (a second one below the loader/spinner was redundant on the same\n\t// screen and got turned off by request), only Claude's own hints.\n\tsettings.statusLine = {\n\t\ttype: \"command\",\n\t\t// Must actually invoke node -- a bare path relies on the OS resolving\n\t\t// a shebang / file association for a plain .js file, which Windows\n\t\t// never does at all and which isn't guaranteed elsewhere either. The\n\t\t// hook entries below already get this right (`node \"${path}\" ...`);\n\t\t// this one silently didn't, so the status line never ran.\n\t\tcommand: `node \"${hookBinPath.replace(\"hook.js\", \"statusline.js\")}\"`,\n\t};\n\n\tsettings.hooks = _mergeHooks(settings.hooks ?? {}, hookBinPath);\n\n\twriteJsonAtomic(claudeSettingsPath(), settings);\n}\n\n/**\n * Called from `hook.ts` on every `UserPromptSubmit` once a fresh ad has been\n * fetched -- swaps the spinner's word for that ad's copy. Only touches\n * `spinnerVerbs`; `statusLine` and `hooks` are left exactly as `enable()`\n * set them, so this is safe to call every turn without re-merging hooks.\n */\nexport function updateSpinnerVerb(verb: string): void {\n\tconst settings = readJsonOwnedByUser<TClaudeSettings>(\n\t\tclaudeSettingsPath(),\n\t\t{},\n\t);\n\tsettings.spinnerVerbs = { mode: \"replace\", verbs: [verb] };\n\twriteJsonAtomic(claudeSettingsPath(), settings);\n}\n\nexport function disable(): void {\n\tconst settings = readJsonOwnedByUser<TClaudeSettings>(\n\t\tclaudeSettingsPath(),\n\t\t{},\n\t);\n\n\tfor (const key of OWNED_KEYS) {\n\t\tdelete (settings as Record<string, unknown>)[key];\n\t}\n\n\tif (settings.hooks) {\n\t\tfor (const event of OWNED_HOOK_EVENTS) {\n\t\t\tconst entries = settings.hooks[event];\n\t\t\tif (!Array.isArray(entries)) continue;\n\t\t\tconst kept = entries.filter((entry) => !_isOwnedHookEntry(entry));\n\t\t\tif (kept.length > 0) {\n\t\t\t\tsettings.hooks[event] = kept;\n\t\t\t} else {\n\t\t\t\tdelete settings.hooks[event];\n\t\t\t}\n\t\t}\n\t\tif (Object.keys(settings.hooks).length === 0) {\n\t\t\t// JSON.stringify drops undefined-valued keys, so this has the same\n\t\t\t// on-disk effect as `delete` without biome's no-delete warning.\n\t\t\tsettings.hooks = undefined;\n\t\t}\n\t}\n\n\twriteJsonAtomic(claudeSettingsPath(), settings);\n}\n\n/** Detects the one setting that silently disables hooks (and therefore\n * `statusLine`) so callers can degrade to spinner-verbs-only and say so. */\nexport function hooksDisabled(): boolean {\n\tconst settings = readJson<TClaudeSettings>(claudeSettingsPath(), {});\n\treturn settings.disableAllHooks === true;\n}\n\nfunction _mergeHooks(\n\thooks: Record<string, unknown[]>,\n\thookBinPath: string,\n): Record<string, unknown[]> {\n\tconst next = { ...hooks };\n\tfor (const event of OWNED_HOOK_EVENTS) {\n\t\tconst existing = (next[event] ?? []).filter(\n\t\t\t(entry) => !_isOwnedHookEntry(entry),\n\t\t);\n\t\tnext[event] = [\n\t\t\t...existing,\n\t\t\t{\n\t\t\t\tmatcher: \"*\",\n\t\t\t\thooks: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"command\",\n\t\t\t\t\t\tcommand: `node \"${hookBinPath}\" ${event} ${_HOOK_MARKER}`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t];\n\t}\n\treturn next;\n}\n\nfunction _isOwnedHookEntry(entry: unknown): boolean {\n\treturn JSON.stringify(entry).includes(_HOOK_MARKER);\n}\n","import { debugLog } from \"./debug\";\nimport { logoCachePath } from \"./paths\";\nimport { readJson, writeJsonAtomic } from \"./store\";\n\n/**\n * Turns a remote logo URL into a `data:` URI, cached on disk keyed by the\n * original URL -- fetched at most once per URL, ever.\n *\n * Why this exists at all: the chat-panel webview's Content-Security-Policy\n * only allows `img-src 'self' https://*.vscode-cdn.net data:` -- confirmed\n * live via the webview's own DevTools console, which showed the exact CSP\n * violation for a raw `https://pbs.twimg.com/...` logo URL. No amount of\n * patching the render function gets around that; it's Chromium's own policy\n * for the webview, enforced independently of anything this extension writes.\n * `data:` URIs are the one exception CSP explicitly allows, so the fix is to\n * embed the image bytes directly instead of linking to them.\n */\n\ntype TLogoCache = Record<string, string>;\n\nconst _FETCH_TIMEOUT_MS = 3000;\n/**\n * Base64 inflates size by ~33%, and this ends up embedded in\n * `~/.claude/settings.json` / `claudeCode.spinnerVerbs` -- both real files a\n * user might open. Capped well under any practical settings-file size limit;\n * an oversized source image just doesn't get a logo, same as a fetch failure.\n *\n * Briefly lowered to 2_000 on the theory that this payload was inflating the\n * chat panel's spinner width and causing the clipped/overlapping ad text.\n * That was wrong, and the cost was real (most advertiser logos fell back to\n * the generic bundled badge). The panel computes its width as\n * `Math.max(...verbs.map(v => v.length))` over the list AFTER\n * `webviewPatch.ts`'s patch has already split each entry into its label --\n * so the width only ever sees the ~26-character label, never the URL or this\n * logo. The actual cause was stale render state in that component; see the\n * `_ANCHORS` doc comment. Restored, so real advertiser logos show again.\n */\nconst _MAX_BYTES = 100_000;\n\n/**\n * Bundled at build time, not fetched -- a tiny vector redraw of the\n * extension's own icon (`assets/icon.png`'s 3x3 grid mark, one cell\n * highlighted), not the raw PNG. Kept as hand-drawn SVG rather than a\n * base64 copy of the real asset for the same reason the old \"K\" badge this\n * replaced was SVG too: this string ends up embedded directly in\n * `claudeCode.spinnerVerbs` inside `~/.claude/settings.json` -- a real file\n * a user might open -- and a ~180-byte vector shape stays negligible there\n * where a base64'd raster (icon.png is ~45KB, ~60KB again once base64\n * inflates it) would not. `data:image/svg+xml` is covered by the same CSP\n * allowance as a base64 raster image, so this needs no network round trip\n * and can never violate the policy that blocked the raw URL in the first\n * place.\n */\nexport const KILI_FALLBACK_LOGO_DATA_URI = `data:image/svg+xml,${encodeURIComponent(\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\"><rect width=\"14\" height=\"14\" rx=\"3\" fill=\"#000\"/>' +\n\t\t'<rect x=\"2\" y=\"2\" width=\"3\" height=\"3\" rx=\"0.6\" fill=\"#D1D5DB\"/>' +\n\t\t'<rect x=\"6\" y=\"2\" width=\"3\" height=\"3\" rx=\"0.6\" fill=\"#D1D5DB\"/>' +\n\t\t'<rect x=\"10\" y=\"2\" width=\"3\" height=\"3\" rx=\"0.6\" fill=\"#22C55E\"/>' +\n\t\t'<rect x=\"2\" y=\"6\" width=\"3\" height=\"3\" rx=\"0.6\" fill=\"#D1D5DB\"/>' +\n\t\t'<rect x=\"6\" y=\"6\" width=\"3\" height=\"3\" rx=\"0.6\" fill=\"#D1D5DB\"/>' +\n\t\t'<rect x=\"10\" y=\"6\" width=\"3\" height=\"3\" rx=\"0.6\" fill=\"#D1D5DB\"/>' +\n\t\t'<rect x=\"2\" y=\"10\" width=\"3\" height=\"3\" rx=\"0.6\" fill=\"#D1D5DB\"/>' +\n\t\t'<rect x=\"6\" y=\"10\" width=\"3\" height=\"3\" rx=\"0.6\" fill=\"#D1D5DB\"/>' +\n\t\t'<rect x=\"10\" y=\"10\" width=\"3\" height=\"3\" rx=\"0.6\" fill=\"#D1D5DB\"/></svg>',\n)}`;\n\nexport function getCachedLogoDataUri(url: string): string | null {\n\tconst cache = readJson<TLogoCache>(logoCachePath(), {});\n\treturn cache[url] ?? null;\n}\n\n/**\n * The logo to actually put in a spinner verb right now, synchronously: the\n * cached real logo if `fetchAndCacheLogoDataUri` already resolved it, the\n * bundled fallback badge otherwise -- never the raw blocked URL, and never\n * nothing (a `Sponsored`-only line with no mark at all reads as less\n * trustworthy than a generic badge, the same reasoning kickbacks.ai's own\n * fallback badge is built on). Callers still need to separately call\n * `fetchAndCacheLogoDataUri` (fire-and-forget) so a later turn can upgrade\n * from the fallback to the real logo once it's cached.\n */\nexport function resolveLogoDataUri(favicon: string | undefined): string {\n\tif (!favicon) return KILI_FALLBACK_LOGO_DATA_URI;\n\treturn getCachedLogoDataUri(favicon) ?? KILI_FALLBACK_LOGO_DATA_URI;\n}\n\n/**\n * Fetches and caches in the background -- never awaited by a caller on the\n * per-turn critical path. Callers should render without a logo on the turn\n * that first sees a new URL, then pick it up from `getCachedLogoDataUri` on\n * a later turn once this has had a chance to complete.\n */\nexport async function fetchAndCacheLogoDataUri(\n\turl: string,\n): Promise<string | null> {\n\tconst cached = getCachedLogoDataUri(url);\n\tif (cached) return cached;\n\n\tconst controller = new AbortController();\n\tconst timer = setTimeout(() => controller.abort(), _FETCH_TIMEOUT_MS);\n\ttry {\n\t\tconst res = await fetch(url, { signal: controller.signal });\n\t\tif (!res.ok) {\n\t\t\tdebugLog(\"logoCache: fetch not ok\", url, res.status);\n\t\t\treturn null;\n\t\t}\n\t\tconst contentType = res.headers.get(\"content-type\") ?? \"image/png\";\n\t\tif (!contentType.startsWith(\"image/\")) {\n\t\t\tdebugLog(\"logoCache: non-image content-type\", url, contentType);\n\t\t\treturn null;\n\t\t}\n\t\tconst buf = await res.arrayBuffer();\n\t\tif (buf.byteLength > _MAX_BYTES) {\n\t\t\tdebugLog(\"logoCache: oversized\", url, buf.byteLength, \"> \", _MAX_BYTES);\n\t\t\treturn null;\n\t\t}\n\t\tconst dataUri = `data:${contentType};base64,${Buffer.from(buf).toString(\"base64\")}`;\n\t\tconst cache = readJson<TLogoCache>(logoCachePath(), {});\n\t\tcache[url] = dataUri;\n\t\twriteJsonAtomic(logoCachePath(), cache);\n\t\tdebugLog(\"logoCache: cached\", url, buf.byteLength, \"bytes\");\n\t\treturn dataUri;\n\t} catch (e) {\n\t\t// A dead/slow/oversized logo URL must never block or fail the ad\n\t\t// itself -- the label and click-through still work with no logo.\n\t\tdebugLog(\"logoCache: fetch threw\", url, e instanceof Error ? e.message : e);\n\t\treturn null;\n\t} finally {\n\t\tclearTimeout(timer);\n\t}\n}\n","import { updateSpinnerVerb } from \"../claude/settings\";\r\nimport { putAd } from \"./cache\";\r\nimport { KiliClient } from \"./client\";\r\nimport { PLACEMENT } from \"./constants\";\r\nimport { spinnerVerb, spinnerVerbLink } from \"./copy\";\r\nimport { debugLog } from \"./debug\";\r\nimport { writeClaudeCodeSpinnerVerbsEverywhereInstalled } from \"./editorSettings\";\r\nimport { fetchAndCacheLogoDataUri, resolveLogoDataUri } from \"./logoCache\";\r\nimport type { TAd, TRuntimeConfig } from \"./types\";\r\n\r\n// `PLACEMENT.TERMINAL_STATUSLINE` and `PLACEMENT.EXTENSION_STATUSBAR`\r\n// deliberately excluded from every group below: `claude/settings.ts`'s\r\n// `enable()` and `terminal.ts`'s `enableTerminalHooks()` no longer set\r\n// `statusLine` at all (a second ad below the loader/spinner on the same\r\n// screen, turned off by request), and the VS Code status bar item stopped\r\n// rendering an ad entirely (`KiliStatusBar.showAd()` removed -- it was a\r\n// second, non-billing copy of the exact same spinner ad, pure visual\r\n// redundancy, and its own independent `claimCurrentImpression` call was the\r\n// second half of a real double-billing bug -- see `ui/statusBar.ts`).\r\n// Requesting either placement now would only serve (and risk billing) an ad\r\n// no one sees anymore.\r\nconst _ALL_PLACEMENTS: string[] = [\r\n\tPLACEMENT.TERMINAL_SPINNER,\r\n\tPLACEMENT.EXTENSION_SPINNER,\r\n];\r\n\r\n/** `hook.ts`'s group -- the surface driven by real per-turn context. */\r\nexport const TERMINAL_PLACEMENTS: string[] = [PLACEMENT.TERMINAL_SPINNER];\r\n\r\n/** `extension.ts`'s idle-timer group -- the one surface it renders itself. */\r\nexport const EXTENSION_PLACEMENTS: string[] = [PLACEMENT.EXTENSION_SPINNER];\r\n\r\n/**\r\n * Fetches every eligible ad for the given surfaces in a single `/ads` call.\r\n *\r\n * Requesting a group of surfaces together, instead of as independent calls,\r\n * is what guarantees they resolve to the same server response rather than\r\n * two separate calls landing on two different picks (relevant whenever\r\n * `AllAdServeStrategy` is configured server-side and returns a shuffled\r\n * multi-ad list; under the currently-configured `RandomAdServeStrategy` each\r\n * call just returns one ad per placement, but the grouping stays correct\r\n * either way).\r\n *\r\n * Callers must pass only the placements *they* own -- `hook.ts` (terminal\r\n * spinner + terminal statusline) and `extension.ts` (extension spinner +\r\n * extension statusbar) must never share a call, even though this function is\r\n * happy to serve either group. They used to always request all four\r\n * together: `hook.ts` ran once per turn, `extension.ts`'s idle timer ran\r\n * every 60s, regardless of whether a turn was even in flight. Because both\r\n * calls wrote into the same cache/settings for all four placements, the idle\r\n * call would periodically stomp the terminal placements back to whatever ad\r\n * the server resolved -- visibly a *different*, seemingly-stuck ad on the\r\n * terminal status line while the loader/spinner (driven by the real per-turn\r\n * call) kept updating normally. Confirmed live: this was happening in prod.\r\n *\r\n * No `messages` param, deliberately: api.kili's ad selection never reads\r\n * conversation content (`RandomAdServeStrategy`/`AllAdServeStrategy` and the\r\n * `IAdServeStrategy` interface itself only ever see `candidates`), so this\r\n * used to send real chat text over the wire for nothing -- see `client.ts`'s\r\n * `_body()`.\r\n *\r\n * Only the *first* ad in each placement's set gets applied here (written to\r\n * the cache, and to `claudeCode.spinnerVerbs` for the extension spinner) --\r\n * under `RandomAdServeStrategy` that's the only ad there is anyway. A turn\r\n * shows exactly this one ad until the next real fetch replaces it: either\r\n * `hook.ts`'s next `UserPromptSubmit` (terminal), or `extension.ts`'s\r\n * turn-start fetch (extension surfaces) -- see that file's doc comments for\r\n * why there is no client-side rotation between real fetches anymore.\r\n *\r\n * Callable from both `hook.ts` (a plain Node process with no `vscode` API)\r\n * and `extension.ts` -- everything here is a file write or a network call,\r\n * nothing needs the extension host. `extension.ts` additionally pushes the\r\n * result into its own status bar item after calling this.\r\n */\r\nexport async function refreshAllPlacements(\r\n\tconfig: TRuntimeConfig,\r\n\tsessionId: string,\r\n\tplacementIds: string[] = _ALL_PLACEMENTS,\r\n): Promise<Map<string, TAd[]>> {\r\n\tconst client = new KiliClient();\r\n\tconst adSets = await client.fetchAds({\r\n\t\tapiKey: config.apiKey,\r\n\t\tapiUrl: config.apiUrl,\r\n\t\tinstallId: config.installId,\r\n\t\tsessionId,\r\n\t\tplacementIds,\r\n\t});\r\n\r\n\t// One line per fetch, with what came back per placement -- the entry\r\n\t// point of the whole per-turn chain, so a `debug.log` read top-to-bottom\r\n\t// shows fetch -> write -> render without having to correlate file mtimes\r\n\t// across three processes by hand.\r\n\tdebugLog(\"refreshAllPlacements\", {\r\n\t\trequested: placementIds,\r\n\t\tgot: [...adSets].map(([id, ads]) => `${id}:${ads.length}`),\r\n\t\tsessionId,\r\n\t});\r\n\r\n\tfor (const [placementId, ads] of adSets) putAd(placementId, ads);\r\n\r\n\tconst terminalAds = adSets.get(PLACEMENT.TERMINAL_SPINNER);\r\n\tif (terminalAds?.[0]) updateSpinnerVerb(spinnerVerb(terminalAds[0]));\r\n\r\n\tconst extensionAds = adSets.get(PLACEMENT.EXTENSION_SPINNER);\r\n\tif (extensionAds?.[0]) applyExtensionSpinnerAd(extensionAds[0], config);\r\n\r\n\treturn adSets;\r\n}\r\n\r\n/** Both verb forms are always computed; which one a given editor actually\r\n * gets is decided per editor inside\r\n * `writeClaudeCodeSpinnerVerbsEverywhereInstalled`, from\r\n * `config.webviewPatchedEditors` -- see that function's doc comment for why\r\n * this can't be a single machine-wide decision (each editor updates Claude\r\n * Code independently, so patch success is too).\r\n *\r\n * Exported: `refreshAllPlacements` above calls this for the extension\r\n * spinner's first ad; `extension.ts`'s turn-start fetch is the other caller,\r\n * invoking `refreshAllPlacements` itself (which reaches this the same way)\r\n * every time a new turn's fetch resolves. */\r\nexport function applyExtensionSpinnerAd(ad: TAd, config: TRuntimeConfig): void {\r\n\t// `ad.favicon`'s raw URL is never usable directly -- the webview's CSP\r\n\t// blocks it outright (`img-src` has no allowance for arbitrary remote\r\n\t// hosts, confirmed live via the webview's own DevTools console). The\r\n\t// cached `data:` URI is the only form CSP actually permits; the bundled\r\n\t// badge covers every turn before that cache is warm. `void`: the fetch\r\n\t// runs in the background and must never delay or fail this turn's write --\r\n\t// a later turn upgrades from the fallback badge once it resolves.\r\n\tconst logo = resolveLogoDataUri(ad.favicon);\r\n\tif (ad.favicon) void fetchAndCacheLogoDataUri(ad.favicon);\r\n\r\n\tconst link = spinnerVerbLink(ad, logo);\r\n\t// KILI_DEBUG=1 only -- the last stop before this either lands as a\r\n\t// clickable, logo'd link in a patched webview, or falls back to plain\r\n\t// text. Confirms whether the ad this turn resolved even had a logo, and\r\n\t// whether any editor was actually patched to receive the encoded form.\r\n\tdebugLog(\"applyExtensionSpinnerAd\", {\r\n\t\tadId: ad.adId,\r\n\t\thasFavicon: Boolean(ad.favicon),\r\n\t\tfavicon: ad.favicon,\r\n\t\tusingFallbackBadge: logo.startsWith(\"data:image/svg+xml\"),\r\n\t\tencodedHasLogoSeparator: [...link].filter((c) => c.codePointAt(0) === 1)\r\n\t\t\t.length,\r\n\t\tpatchedEditors: config.webviewPatchedEditors,\r\n\t});\r\n\twriteClaudeCodeSpinnerVerbsEverywhereInstalled([spinnerVerb(ad)], [link]);\r\n}\r\n","#!/usr/bin/env node\nimport {\n\tisTerminalActive,\n\tsettlePendingTurn,\n\tstartPendingTurn,\n} from \"./core/cache\";\nimport { readRuntimeConfig, toSessionId } from \"./core/config\";\nimport { PLACEMENT } from \"./core/constants\";\nimport { RESET_VERBS } from \"./core/copy\";\nimport { debugLog } from \"./core/debug\";\nimport { writeClaudeCodeSpinnerVerbsEverywhereInstalled } from \"./core/editorSettings\";\nimport { TERMINAL_PLACEMENTS, refreshAllPlacements } from \"./core/refresh\";\n\n/**\n * `UserPromptSubmit` / `Stop` hook entry, run by Claude Code once per turn.\n *\n * MUST NEVER PRINT TO STDOUT. `UserPromptSubmit`'s stdout is injected into\n * the model's own context -- any ad copy printed here would be read by\n * Claude as if the user had typed it. Debug output goes to stderr only, and\n * only under `KILI_DEBUG=1`. Always exits 0: a broken ad fetch must never\n * block or fail a user's turn.\n */\nasync function main() {\n\tconst event = process.argv[2];\n\ttry {\n\t\tconst stdin = await _readStdin();\n\t\tconst payload = _parsePayload(stdin);\n\n\t\tif (event === \"UserPromptSubmit\") {\n\t\t\tawait _onUserPromptSubmit(payload);\n\t\t} else if (event === \"Stop\") {\n\t\t\tawait settlePendingTurn();\n\t\t\t_clearSpinnerAfterTurn();\n\t\t}\n\t} catch (error) {\n\t\tdebugLog(\"hook error\", event, error);\n\t}\n\tprocess.exit(0);\n}\n\n/**\n * Clears the finished turn's ad at `Stop`, so nothing stale is left behind\n * for the NEXT turn to flash on screen.\n *\n * The reset used to happen only at `UserPromptSubmit`, i.e. at the start of\n * the next turn. That is structurally too late: the spinner component mounts\n * and reads `claudeCode.spinnerVerbs` as the turn begins, and this hook\n * (a freshly spawned Node process) cannot write the new value before that\n * first read. So the previous ad was always shown for a moment, then\n * replaced -- exactly the reported \"shows the old ad for a little sec\".\n *\n * Clearing here instead means the setting already reads `RESET_VERBS` while\n * idle, so the next turn's very first render has nothing stale to show. This\n * costs nothing visually: the spinner is only rendered while Claude is\n * working, so between turns there is no visible surface to have cleared.\n * `UserPromptSubmit` still resets too, as a safety net for a turn whose\n * `Stop` never fired (interrupted, crashed, or a session that ended\n * mid-response).\n *\n * Impression billing is unaffected -- that already fired when the ad was\n * fetched and rendered, not here (see `claimCurrentImpression`).\n */\nfunction _clearSpinnerAfterTurn(): void {\n\tconst config = readRuntimeConfig();\n\tif (!config || !config.enabled) return;\n\tif (isTerminalActive()) return; // terminal draws its own verb, nothing to reset\n\twriteClaudeCodeSpinnerVerbsEverywhereInstalled(RESET_VERBS, RESET_VERBS);\n\tdebugLog(\"clearSpinnerAfterTurn: reset panel verb\");\n}\n\ntype TPayload = {\n\tsessionId: string | undefined;\n\tuserInput: string | undefined;\n};\n\nasync function _onUserPromptSubmit(payload: TPayload): Promise<void> {\n\tconst config = readRuntimeConfig();\n\tif (!config || !config.enabled) return;\n\n\tconst sessionId = toSessionId(payload.sessionId);\n\n\t// Exactly one spinner surface, never both. `UserPromptSubmit`/`Stop` fire\n\t// identically regardless of which UI is actually rendering this session,\n\t// so without this a single turn used to settle -- and bill -- an\n\t// impression for whichever surface *wasn't* even open, every time (see\n\t// `isTerminalActive`'s doc comment). Computed before the fetch below,\n\t// not after: the panel branch needs it immediately, to clear the previous\n\t// ad as early as possible (see the block right below).\n\tconst terminalActive = isTerminalActive();\n\n\t// IDE panel case only: clear `claudeCode.spinnerVerbs` synchronously,\n\t// before doing anything else -- this hook BLOCKS Claude Code's own turn\n\t// from starting until it exits, so this is the earliest point in the\n\t// entire turn lifecycle that can ever clear the previous turn's ad.\n\t// `extension.ts`'s own per-turn fetch (`_checkForNewTurn`) can't act this\n\t// fast: it's a long-running process decoupled from Claude Code's turn\n\t// lifecycle, polling `~/.kili/pending-turn.json` (which this function\n\t// writes, further below) up to `_TURN_POLL_INTERVAL_MS` late. Without\n\t// this write here, the previous turn's ad stayed visible for that whole\n\t// window -- confirmed live.\n\t//\n\t// Written as `RESET_VERBS` (\"Thinking…\"), NOT `undefined` -- see that\n\t// constant's doc comment: deleting `claudeCode.spinnerVerbs` does not\n\t// visibly reset the panel at all, because Claude Code's webview keeps the\n\t// last verbs it read in memory and only re-renders on a *new* value.\n\t// Confirmed live: with a delete here, the previous turn's ad stayed on\n\t// screen for the entire 4.7s until the real ad landed, which is exactly\n\t// the \"still shows the previous ad, no thinking text\" report this is\n\t// fixing.\n\t//\n\t// No `EXTENSION_STATUSBAR` counterpart here -- that status bar item is a\n\t// separate UI element `extension.ts` resets on its own (`showIdle`), not\n\t// `claudeCode.spinnerVerbs`.\n\tif (!terminalActive) {\n\t\twriteClaudeCodeSpinnerVerbsEverywhereInstalled(RESET_VERBS, RESET_VERBS);\n\t}\n\n\t// Deliberately does NOT re-assert the last cached ad before this fetch\n\t// (see `reapplyCachedSpinnerVerbs`'s doc comment for the tradeoff it was\n\t// built to close): doing so could flash a *stale* ad from a previous\n\t// turn/session -- possibly still on the logo fallback badge, or already\n\t// upgraded -- ahead of this turn's real one, landing as a visible\n\t// three-step flicker (stale ad -> reset -> fresh ad) that read worse\n\t// than the brief default-verb flash it was meant to prevent. Waiting for\n\t// the real fetch below is the more honest state to show, on request.\n\t// Scoped to `TERMINAL_PLACEMENTS` -- this call must never also touch\n\t// `EXTENSION_SPINNER`/`EXTENSION_STATUSBAR`. Those belong solely to\n\t// `extension.ts`'s idle timer (`EXTENSION_PLACEMENTS`); this hook running\n\t// with no explicit placements would fall back to `refreshAllPlacements`'s\n\t// default of all three, racing that timer's own writes to the same two\n\t// placements on every turn -- confirmed live: this produced a cache where\n\t// `extension_spinner` and `extension_statusbar` disagreed, each holding\n\t// whichever call's write landed last for that one placement.\n\tconst ads = await refreshAllPlacements(\n\t\tconfig,\n\t\tsessionId,\n\t\tTERMINAL_PLACEMENTS,\n\t);\n\n\t// The two branches below are NOT symmetric, on purpose:\n\t// - terminalActive: `ads` really was fetched for `TERMINAL_SPINNER`\n\t// (see the `TERMINAL_PLACEMENTS`-scoped call above), so `ads.has()`\n\t// is a meaningful check -- it's `false` only when api.kili genuinely\n\t// had nothing to serve (no active campaign), and skipping\n\t// `startPendingTurn` in that case is correct: nothing to settle later.\n\t// - !terminalActive (the IDE chat panel): `ads` was NEVER fetched for\n\t// `EXTENSION_SPINNER` at all -- that placement is deliberately outside\n\t// this hook's own `TERMINAL_PLACEMENTS`-scoped fetch (see the comment\n\t// above `refreshAllPlacements`). Gating this branch on `ads.has()`\n\t// too, as this code used to, meant the check was checking something\n\t// that was structurally never true regardless of whether an ad\n\t// existed -- `startPendingTurn` silently never fired for a single\n\t// panel turn, ever. Confirmed live: the panel spinner never advanced\n\t// off the extension's own 60s idle-timer cadence, no matter how many\n\t// messages were sent, because nothing ever wrote the pending-turn\n\t// record `extension.ts`'s per-turn fetch (`_checkForNewTurn`) polls\n\t// for. This branch is unconditional instead -- `extension.ts`'s own\n\t// fetch, triggered BY this pending-turn record existing, is what\n\t// actually resolves (or fails to resolve) an ad for this placement;\n\t// `settlePendingTurn` at `Stop` already no-ops safely if that fetch\n\t// never produced anything to settle.\n\tconst settledPlacements: string[] = terminalActive\n\t\t? ads.has(PLACEMENT.TERMINAL_SPINNER) ? [PLACEMENT.TERMINAL_SPINNER] : []\n\t\t: [PLACEMENT.EXTENSION_SPINNER];\n\tdebugLog(\"onUserPromptSubmit\", {\n\t\tterminalActive,\n\t\tsettledPlacements,\n\t});\n\n\tif (settledPlacements.length > 0) {\n\t\tstartPendingTurn({\n\t\t\tsessionId,\n\t\t\tplacementIds: settledPlacements,\n\t\t\tstartedAt: Date.now(),\n\t\t});\n\t}\n}\n\nfunction _readStdin(): Promise<string> {\n\treturn new Promise((resolve) => {\n\t\tlet data = \"\";\n\t\tprocess.stdin.setEncoding(\"utf8\");\n\t\tprocess.stdin.on(\"data\", (chunk) => {\n\t\t\tdata += chunk;\n\t\t});\n\t\tprocess.stdin.on(\"end\", () => resolve(data));\n\t\tprocess.stdin.on(\"error\", () => resolve(data));\n\t\t// Hooks always receive JSON on stdin, but guard against a hang if\n\t\t// Claude Code ever calls this without piping anything.\n\t\tsetTimeout(() => resolve(data), 2000);\n\t});\n}\n\nfunction _parsePayload(raw: string): TPayload {\n\ttry {\n\t\tconst json = JSON.parse(raw) as Record<string, unknown>;\n\t\treturn {\n\t\t\tsessionId:\n\t\t\t\ttypeof json.session_id === \"string\" ? json.session_id : undefined,\n\t\t\tuserInput:\n\t\t\t\ttypeof json.user_input === \"string\"\n\t\t\t\t\t? json.user_input\n\t\t\t\t\t: typeof json.prompt === \"string\"\n\t\t\t\t\t\t? json.prompt\n\t\t\t\t\t\t: undefined,\n\t\t};\n\t} catch {\n\t\treturn { sessionId: undefined, userInput: undefined };\n\t}\n}\n\nvoid main();\n"],"mappings":"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I;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAA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","names":["import_node_path","import_node_fs","import_node_path","value","CharacterCodes","ParseOptions","ScanError","SyntaxKind","parse","ParseErrorCode","parse","import_node_crypto","import_node_fs","import_node_os","import_node_path","import_node_fs","import_node_os","import_node_path","import_node_fs","import_node_path","_MAX_BYTES"]}
Binary file
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kili-ai/dev-install",
3
3
  "description": "npx installer for Kili for Claude Code. Finds your editors (VS Code / Cursor / VSCodium), installs the @kili-ai/ide extension, and signs you in through your browser.",
4
- "version": "0.2.64",
4
+ "version": "0.2.65",
5
5
  "license": "MIT",
6
6
  "packageManager": "pnpm@10.2.0",
7
7
  "engines": {