@kili-ai/dev-install 0.2.64

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/client.ts","../src/core/constants.ts","../src/core/debug.ts","../src/core/paths.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/webviewPatch.ts","../src/core/copy.ts","../src/statusline.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","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 {\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","#!/usr/bin/env node\nimport { touchTerminalHeartbeat } from \"./core/cache\";\nimport { dim } from \"./core/copy\";\n\n/**\n * Spawned fresh by Claude Code every ~300ms (debounced, in-flight cancelled\n * on the next update). Never renders an ad -- a second one below the\n * loader/spinner was redundant on the same screen and got turned off by\n * request (see `PLACEMENT.TERMINAL_STATUSLINE`'s removal from\n * `core/refresh.ts`'s placement groups). This script keeps running anyway,\n * for two reasons that have nothing to do with what it prints:\n *\n * 1. Its own invocation is `isTerminalActive`'s only signal that a real\n * terminal, not the IDE chat panel, is currently in front of the user --\n * `hook.ts` uses that to decide which single surface a turn's spinner\n * impression belongs to. Removing `statusLine` entirely would silently\n * misattribute every terminal turn to the extension surface instead.\n * 2. Claude Code's own `esc to interrupt` / `? for shortcuts` hints are\n * hidden once `statusLine` is configured at all, ad or not -- re-rendering\n * them here is what keeps that affordance from just disappearing.\n */\nfunction main() {\n\ttouchTerminalHeartbeat();\n\tprocess.stdout.write(dim(\"esc to interrupt · ? for shortcuts\"));\n}\n\nmain();\n"],"mappings":";;;;AAAA,yBAA2B;;;ACOpB,IAAM,UAAU;AAChB,IAAM,cAAc;AACpB,IAAM,eAAe,IAAI,OAAO,IAAI,WAAW;AAwB/C,IAAM,kBAAkB,IAAI,KAAK;;;ACjCxC,qBAAgE;AAChE,IAAAA,oBAAkC;;;ACDlC,qBAAwB;AACxB,uBAAqB;AAId,SAAS,WAAmB;AAClC,aAAO,2BAAK,wBAAQ,GAAG,OAAO;AAC/B;AAyBO,SAAS,wBAAgC;AAC/C,aAAO,uBAAK,SAAS,GAAG,yBAAyB;AAClD;;;AClCA,IAAAC,kBAOO;AACP,IAAAC,oBAAwB;;;ACgWxB,IAAI;AAAA,CACH,SAAUC,iBAAgB;AACvB,EAAAA,gBAAeA,gBAAe,UAAU,IAAI,EAAE,IAAI;AAClD,EAAAA,gBAAeA,gBAAe,gBAAgB,IAAI,EAAE,IAAI;AACxD,EAAAA,gBAAeA,gBAAe,OAAO,IAAI,EAAE,IAAI;AAC/C,EAAAA,gBAAeA,gBAAe,IAAI,IAAI,EAAE,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,IAAI,IAAI,EAAE,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,IAAI,IAAI,EAAE,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,IAAI,IAAI,EAAE,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,IAAI,IAAI,EAAE,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,IAAI,IAAI,EAAE,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,IAAI,IAAI,EAAE,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,IAAI,IAAI,EAAE,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,IAAI,IAAI,EAAE,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,IAAI,IAAI,EAAE,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,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,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,E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","names":["import_node_path","import_node_fs","import_node_path","CharacterCodes","ParseOptions","ScanError","SyntaxKind","ParseErrorCode","import_node_fs","import_node_os","import_node_path"]}
Binary file
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@kili-ai/dev-install",
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",
5
+ "license": "MIT",
6
+ "packageManager": "pnpm@10.2.0",
7
+ "engines": {
8
+ "node": ">=22.0.0"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/scribble-dao/pkg.install.kili.git"
13
+ },
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "bin": {
18
+ "kili-install": "dist/index.js"
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "CHANGELOG.md"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsup && node scripts/copy-vsix.cjs && node scripts/copy-terminal-bin.cjs",
26
+ "dev": "tsup --watch",
27
+ "lint": "biome lint --write ./src",
28
+ "check": "biome ci ./src",
29
+ "format": "biome format --write ./src",
30
+ "test": "vitest run",
31
+ "prepublishOnly": "pnpm test && pnpm build",
32
+ "publish:prod": "node scripts/publish-channel.cjs prod",
33
+ "publish:dev": "node scripts/publish-channel.cjs dev",
34
+ "changeset": "changeset",
35
+ "changeset:status": "changeset status",
36
+ "changeset:version": "changeset version",
37
+ "changeset:publish": "changeset publish"
38
+ },
39
+ "dependencies": {
40
+ "jsonc-parser": "^3.3.1",
41
+ "open": "^10.1.0"
42
+ },
43
+ "devDependencies": {
44
+ "@biomejs/biome": "1.9.3",
45
+ "@changesets/cli": "^3.0.0",
46
+ "@types/node": "^20.3.1",
47
+ "tsup": "^8.0.1",
48
+ "typescript": "^5.1.3",
49
+ "vitest": "^1.6.0"
50
+ }
51
+ }