{"owner":"freelensapp","repo":"freelens","hasSkills":true,"totalSkillsCount":140,"totalTokensCount":52231,"categories":["anthropic-skill","claude-rule","plugin-manifest","root-instruction"],"hasMcp":false,"mcpConfig":null,"found":["packages/semver/tsconfig.json","packages/routing/tsconfig.json","packages/semver/package.json","packages/routing/package.json","packages/resource-templates/package.json","packages/random/package.json","packages/random/tsconfig.json","packages/metrics/package.json","CLAUDE.md","packages/random/README.md","packages/routing/README.md","AGENTS.md","packages/metrics/tsconfig.json","packages/logger/package.json","packages/logger/README.md","packages/logger/tsconfig.json","packages/list-layout/package.json","packages/list-layout/tsconfig.json","packages/kubectl-versions/package.json","packages/kubectl-versions/README.md","packages/kubectl-versions/tsconfig.json","packages/kube-object/package.json","packages/kube-object/tsconfig.json","packages/generate-tray-icons/package.json","packages/generate-tray-icons/tsconfig.json","packages/generate-license/package.json","packages/generate-license/tsconfig.json","packages/extensions/package.json","packages/extensions/tsconfig.dts.json","packages/extensions/tsconfig.json","packages/ensure-binaries/package.json","packages/ensure-binaries/tsconfig.json","packages/core/package.json","packages/core/tsconfig.json","packages/cluster-sidebar/package.json","packages/cluster-sidebar/tsconfig.json","packages/cluster-settings/package.json","packages/cluster-settings/README.md","packages/cluster-settings/tsconfig.json","packages/utility-features/utilities/package.json","packages/utility-features/utilities/README.md","packages/utility-features/utilities/tsconfig.json","packages/utility-features/test-utils/package.json","packages/utility-features/test-utils/README.md","packages/utility-features/test-utils/tsconfig.json","packages/utility-features/startable-stoppable/package.json","packages/utility-features/startable-stoppable/tsconfig.json","packages/utility-features/run-many/package.json","packages/utility-features/run-many/README.md","packages/utility-features/run-many/tsconfig.json","packages/utility-features/react-testing-library-discovery/package.json","packages/utility-features/react-testing-library-discovery/tsconfig.json","packages/utility-features/kube-api-specifics/package.json","packages/utility-features/kube-api-specifics/tsconfig.json","packages/utility-features/kube-api/package.json","packages/utility-features/kube-api/tsconfig.json","packages/utility-features/json-api/package.json","packages/utility-features/json-api/tsconfig.json","packages/utility-features/event-emitter/package.json","packages/utility-features/event-emitter/tsconfig.json","packages/ui-components/tooltip/package.json","packages/ui-components/tooltip/README.md","packages/ui-components/tooltip/tsconfig.json","packages/ui-components/spinner/package.json","packages/ui-components/spinner/README.md","packages/ui-components/spinner/tsconfig.json","packages/ui-components/resizing-anchor/package.json","packages/ui-components/resizing-anchor/README.md","packages/ui-components/resizing-anchor/tsconfig.json","packages/ui-components/notifications/package.json","packages/ui-components/notifications/README.md","packages/ui-components/notifications/tsconfig.json","packages/ui-components/icon/package.json","packages/ui-components/icon/README.md","packages/ui-components/icon/tsconfig.json","packages/ui-components/error-boundary/package.json","packages/ui-components/error-boundary/README.md","packages/ui-components/error-boundary/tsconfig.json","packages/ui-components/button/package.json","packages/ui-components/button/README.md","packages/ui-components/button/tsconfig.json","packages/ui-components/animate/package.json","packages/ui-components/animate/README.md","packages/ui-components/animate/tsconfig.json","packages/technical-features/react-application/package.json","packages/technical-features/react-application/README.md","packages/technical-features/react-application/tsconfig.json","packages/technical-features/prometheus/package.json","packages/technical-features/prometheus/tsconfig.json","packages/technical-features/feature-core/package.json","packages/technical-features/feature-core/README.md","packages/technical-features/feature-core/tsconfig.json","packages/resource-templates/templates/.yamlfmt.yaml","packages/kubectl-versions/build/checksums.json","packages/kubectl-versions/build/tsconfig.json","packages/kubectl-versions/build/versions.json","packages/infrastructure/typescript/package.json","packages/infrastructure/typescript/README.md","packages/business-features/keyboard-shortcuts/package.json","packages/business-features/keyboard-shortcuts/README.md","packages/business-features/keyboard-shortcuts/tsconfig.json","packages/technical-features/messaging/messaging-for-renderer/package.json","packages/technical-features/messaging/messaging-for-renderer/tsconfig.json","packages/technical-features/messaging/messaging-for-main/package.json","packages/technical-features/messaging/messaging-for-main/tsconfig.json","packages/technical-features/messaging/messaging-fake-bridge/package.json","packages/technical-features/messaging/messaging-fake-bridge/tsconfig.json","packages/technical-features/messaging/messaging/package.json","packages/technical-features/messaging/messaging/tsconfig.json","packages/technical-features/messaging/computed-channel/package.json","packages/technical-features/messaging/computed-channel/tsconfig.json","packages/technical-features/application/application-for-electron-main/package.json","packages/technical-features/application/application-for-electron-main/README.md","packages/technical-features/application/application-for-electron-main/tsconfig.json","packages/technical-features/application/application/package.json","packages/technical-features/application/application/README.md","packages/technical-features/application/application/tsconfig.json","packages/resource-templates/templates/create-resource/ClusterRole.yaml","packages/resource-templates/templates/create-resource/ClusterRoleBinding.yaml","packages/resource-templates/templates/create-resource/ConfigMap.yaml","packages/resource-templates/templates/create-resource/CronJob.yaml","packages/resource-templates/templates/create-resource/DaemonSet.yaml","packages/resource-templates/templates/create-resource/Deployment.yaml","packages/resource-templates/templates/create-resource/Ingress.yaml","packages/resource-templates/templates/create-resource/Job.yaml","packages/resource-templates/templates/create-resource/Namespace.yaml","packages/resource-templates/templates/create-resource/NetworkPolicy.yaml","packages/resource-templates/templates/create-resource/PersistentVolume.yaml","packages/resource-templates/templates/create-resource/PersistentVolumeClaim.yaml","packages/resource-templates/templates/create-resource/Pod.yaml","packages/resource-templates/templates/create-resource/PriorityClass.yaml","packages/resource-templates/templates/create-resource/ReplicaSet.yaml","packages/resource-templates/templates/create-resource/ReplicationController.yaml","packages/resource-templates/templates/create-resource/Role.yaml","packages/resource-templates/templates/create-resource/RoleBinding.yaml","packages/resource-templates/templates/create-resource/RuntimeClass.yaml","packages/resource-templates/templates/create-resource/Secret.yaml","packages/resource-templates/templates/create-resource/Service.yaml","packages/resource-templates/templates/create-resource/StatefulSet.yaml","packages/infrastructure/typescript/config/base.json"],"skills":{"packages/semver/tsconfig.json":"{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"dist/\",\n    \"rootDir\": \"src/\",\n    \"types\": [\"node\"]\n  },\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"node_modules\"]\n}\n","packages/routing/tsconfig.json":"{\n  \"extends\": \"@freelensapp/typescript/config/base.json\",\n  \"include\": [\"**/*.ts\", \"**/*.tsx\"]\n}\n","packages/semver/package.json":"{\n  \"name\": \"@freelensapp/semver\",\n  \"version\": \"2.0.0-0\",\n  \"private\": true,\n  \"description\": \"CLI over verkit package for picking parts of a version\",\n  \"homepage\": \"https://freelens.app\",\n  \"bugs\": {\n    \"url\": \"https://github.com/freelensapp/freelens/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/freelensapp/freelens.git\"\n  },\n  \"license\": \"MIT\",\n  \"author\": {\n    \"name\": \"Freelens Authors\",\n    \"email\": \"freelens@freelens.app\"\n  },\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"tsc --pretty --project .\",\n    \"build:dev\": \"tsc --pretty --project .\",\n    \"clean:dist\": \"pnpm dlx rimraf@6.1.3 dist\"\n  },\n  \"dependencies\": {\n    \"command-line-args\": \"catalog:\",\n    \"verkit\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@types/command-line-args\": \"catalog:\",\n    \"@types/node\": \"catalog:\",\n    \"typescript\": \"catalog:\"\n  }\n}\n","packages/routing/package.json":"{\n  \"name\": \"@freelensapp/routing\",\n  \"version\": \"2.0.0-0\",\n  \"private\": true,\n  \"description\": \"Highly extendable routing in the Freelens.\",\n  \"homepage\": \"https://freelens.app\",\n  \"bugs\": {\n    \"url\": \"https://github.com/freelensapp/freelens/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/freelensapp/freelens.git\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"author\": {\n    \"name\": \"Freelens Authors\",\n    \"email\": \"freelens@freelens.app\"\n  },\n  \"main\": \"./index.ts\",\n  \"types\": \"./index.ts\",\n  \"scripts\": {},\n  \"dependencies\": {\n    \"@freelensapp/feature-core\": \"workspace:^\",\n    \"@ogre-tools/fp\": \"catalog:\",\n    \"@ogre-tools/injectable\": \"catalog:\",\n    \"@ogre-tools/injectable-react\": \"catalog:\",\n    \"mobx\": \"catalog:\",\n    \"mobx-react\": \"catalog:\",\n    \"react\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@freelensapp/typescript\": \"workspace:^\",\n    \"@ogre-tools/injectable-extension-for-mobx\": \"catalog:\",\n    \"@testing-library/jest-dom\": \"catalog:\",\n    \"@testing-library/react\": \"catalog:\",\n    \"@testing-library/user-event\": \"catalog:\",\n    \"@types/react\": \"catalog:\",\n    \"@types/react-dom\": \"catalog:\",\n    \"react-dom\": \"catalog:\",\n    \"vitest\": \"catalog:\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  }\n}\n","packages/resource-templates/package.json":"{\n  \"name\": \"@freelensapp/resource-templates\",\n  \"version\": \"2.0.0-0\",\n  \"private\": true,\n  \"homepage\": \"https://freelens.app\",\n  \"bugs\": {\n    \"url\": \"https://github.com/freelensapp/freelens/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/freelensapp/freelens.git\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"author\": {\n    \"name\": \"Freelens Authors\",\n    \"email\": \"freelens@freelens.app\"\n  },\n  \"files\": [\n    \"templates/**/*\"\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"copyright\": \"© 2023 OpenLens Authors\"\n}\n","packages/random/package.json":"{\n  \"name\": \"@freelensapp/random\",\n  \"version\": \"2.0.0-0\",\n  \"private\": true,\n  \"description\": \"Highly extendable random in the Freelens.\",\n  \"homepage\": \"https://freelens.app\",\n  \"bugs\": {\n    \"url\": \"https://github.com/freelensapp/freelens/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/freelensapp/freelens.git\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"author\": {\n    \"name\": \"Freelens Authors\",\n    \"email\": \"freelens@freelens.app\"\n  },\n  \"exports\": {\n    \".\": \"./index.ts\"\n  },\n  \"main\": \"./index.ts\",\n  \"types\": \"./index.ts\",\n  \"scripts\": {},\n  \"dependencies\": {\n    \"@freelensapp/feature-core\": \"workspace:^\",\n    \"@ogre-tools/injectable\": \"catalog:\",\n    \"uuid\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@freelensapp/typescript\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  }\n}\n","packages/random/tsconfig.json":"{\n  \"extends\": \"@freelensapp/typescript/config/base.json\",\n  \"include\": [\"**/*.ts\", \"**/*.tsx\"]\n}\n","packages/metrics/package.json":"{\n  \"name\": \"@freelensapp/metrics\",\n  \"version\": \"2.0.0-0\",\n  \"private\": true,\n  \"description\": \"Injection tokens for implementing metrics for Freelens\",\n  \"homepage\": \"https://freelens.app\",\n  \"bugs\": {\n    \"url\": \"https://github.com/freelensapp/freelens/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/freelensapp/freelens.git\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"author\": {\n    \"name\": \"Freelens Authors\",\n    \"email\": \"freelens@freelens.app\"\n  },\n  \"main\": \"./index.ts\",\n  \"types\": \"./index.ts\",\n  \"scripts\": {\n    \"clean:dist\": \"pnpm dlx rimraf@6.1.3 dist\"\n  },\n  \"dependencies\": {\n    \"@ogre-tools/injectable\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@freelensapp/kube-object\": \"workspace:^\",\n    \"@freelensapp/typescript\": \"workspace:^\",\n    \"@types/react\": \"catalog:\",\n    \"react\": \"catalog:\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  }\n}\n","CLAUDE.md":"@AGENTS.md\n\n# Agent Guide\n\nThis project uses AGENTS.md as the canonical agent guide (imported above).\nClaude Code reads it via @AGENTS.md, while other agents read it directly.\n","packages/random/README.md":"# @freelensapp/random\n\nThis package contains stuff related to creating Lens-applications. \n\n## Usage\n\n```sh\nnpm install @freelensapp/random\n```\n\n```typescript\nexport type { ... } from \"@freelensapp/random\";\n```\n\n## Extendability\n","packages/routing/README.md":"# @freelensapp/routing\n\nThis package contains stuff related to creating Lens-applications. \n\n## Usage\n\n```sh\nnpm install @freelensapp/routing\n```\n\n```typescript\nimport { observableHistoryInjectable } from \"@freelensapp/routing\";\nimport { searchParamsOptions } from \"@freelensapp/routing\";\n```\n\n## Extendability\n","AGENTS.md":"# Agent Guide: Freelens Development\n\n## Overview\n\nThis guide helps AI agents understand the Freelens codebase, common development tasks, troubleshooting patterns, and key architectural decisions. Use this as a reference when working on the project.\n\nFor local development environment setup and extra development tips, see DEVELOPMENT.md.\n\n- **`freelens/`** - Main Electron application\n  - `src/main/` - Main Electron process code\n  - `src/renderer/` - Renderer process (UI) code\n  - `src/common/` - Shared code between processes\n- **`packages/core/`** - Core functionality\n  - `src/features/` - Feature modules organized by domain\n  - `src/renderer/` - Renderer-specific utilities\n  - `src/extensions/` - Extension system\n- **`packages/`** - Monorepo packages (utilities, components, etc.)\n- **`scripts/`** - Build and development scripts\n\n## Security\n\nNever read, display, reference, or include the contents of the following files in any response or context, even if they are open in the editor:\n\n- `.env`\n- `.env.*`\n- `.envrc`\n- `.npmrc`\n- `*.jks`\n- `*.keystore`\n- `*.p12`\n- `*.pfx`\n- `*.pem`\n- `*.key`\n\nThe same list is git-ignored in `.gitignore` and enforced for Claude Code by\nthe `permissions.deny` rules in `.claude/settings.json`, which block reading\nand editing these files. Change all three together. The rules are native\npermissions rather than a hook on purpose: a hook runs a process in the\nworking tree, which may be an untrusted pull request, and an interpreter such\nas `python3 -c` imports modules from that tree before the hook's own code.\n\n## Session and temporary files\n\nFiles created while working on a task — scratch scripts, command output,\nscreenshots, DOM/accessibility snapshots, and AI-agent / MCP-server runtime\nartifacts — must never be written into the tracked working tree, or they leak\ninto git history. Write them to a system temporary directory outside the repo\n(e.g. under `$TMPDIR`, or `mktemp -d`), not to the repo root.\n\nWhen a tool insists on writing inside the repo, keep it out of git:\n\n- point it at a temp path if it accepts one (e.g. pass an absolute\n  `$TMPDIR/...` filename), otherwise\n- git-ignore its default output directory. Already ignored:\n  `.playwright-mcp/` (Playwright MCP), `logs/` (electron-mcp-server).\n\nNever `git add -A` / `git add .` blindly: review `git status` first and stage\nonly the files your change actually touches, never these artifacts.\n\n### Running a scratch script with the project's toolchain\n\nmise picks the pinned Node from the `mise.toml` of the current directory, so a\nscript outside the repository runs on whatever Node is global unless mise is\npointed at the repository. `mise -C <repo>` (`--cd`) does that by changing the\nworking directory before it runs the command, which also moves where relative\npaths resolve: `mise -C <repo> exec -- node spike.mjs`, run from the script's\ndirectory, looks for `<repo>/spike.mjs` and fails with `Cannot find module`.\nRun from the repository and pass the script by its absolute path instead:\n\n```sh\ncd <repo> && mise exec -- node \"$TMPDIR/spike/spike.mjs\"\n```\n\nThe same applies to every relative argument of the command, input and output\nfiles included.\n\nA script outside the tree does not resolve the project's dependencies either:\nNode looks for `node_modules` next to the script, not in the working\ndirectory. Resolve them from the package that declares them, so the script\ngets the versions the application uses:\n\n```js\nimport { createRequire } from \"node:module\";\n\nconst require = createRequire(\"<repo>/packages/core/package.json\");\nconst { Agent, fetch } = require(\"undici\");\n```\n\nSource files carry one of two header variants. Which one a file gets depends\non whether it continues code from the original OpenLens fork, not on what its\nneighbours in the same directory look like.\n\n**New files** — anything created from scratch, including rewrites,\ntranslations, and reimplementations of removed or legacy logic — get the\nsingle-line variant:\n\n```ts\n/**\n * Copyright (c) Freelens Authors. All rights reserved.\n * Licensed under MIT License. See LICENSE in root directory for more information.\n */\n```\n\nThis holds even when the new file's logic is inspired by, or replaces, old\nOpenLens code: inspiration is not continuation. `freelens/electron.vite.config.ts`,\nwritten as a translation of the removed webpack config, is a new file.\n\n**Files that continue code from the fork** keep the two-line variant:\n\n```ts\n/**\n * Copyright (c) Freelens Authors. All rights reserved.\n * Copyright (c) OpenLens Authors. All rights reserved.\n * Licensed under MIT License. See LICENSE in root directory for more information.\n */\n```\n\nA file continues fork code when its path was present in the fork-import commit\n`0a5798c9` (\"First commit - Open Lens fork from master branch\"):\n\n```sh\ngit ls-tree -r --name-only 0a5798c9 | grep -x <path>\n```\n\nor when `git log --follow -- <path>` traces it back to a path that was — that\nis, git itself detects the file as a rename, move, or copy of fork-era code:\n\n```sh\ngit log --follow --format= --name-only -- <path> | sort -u\n```\n\nNever add the `OpenLens Authors` line to a file that does not already have it\njust because neighbouring files do. Do not touch legal or license text\n(`LICENSE`, `README.md`, `freelens/license-header.txt`,\n`freelens/static/build/license.txt`) or the upstream copyright notices of\nvendored third-party code, which are unrelated to either header variant.\n\nSee [#2352](https://github.com/freelensapp/freelens/issues/2352) for the\ncleanup that established this rule.\n\n## Comments in JSON\n\nComments belong in `.jsonc`, never in `.json` — regardless of what the consuming\nparser tolerates. TypeScript accepts `//` inside a `tsconfig.json`, and so do\nseveral other tools, but anything that reads the file as strict JSON because of\nits extension (`JSON.parse`, `jq`, an editor, a CI script) fails on it. No\n`.json` file in this repository has comments, `tsconfig*.json` included;\n`knip.jsonc` is where a commented configuration lives, and that is the right\npattern.\n\nWhen a `.json` file needs an explanation — why an entry is excluded, why a\nversion is pinned — put it somewhere it survives: the package README, this\nfile, or the pull request that introduced it. Do not smuggle it into the JSON.\n\n## Volatile Facts in Documentation\n\nDocumentation — `docs/`, the READMEs, this file — describes how things are,\nand has to stay true without anyone maintaining it. Keep out of it whatever\ngoes stale on its own:\n\n- issue and pull-request numbers,\n- dates,\n- counts that change without the document changing: how many extensions use\n  something, how many members a namespace has, how many files import a module,\n- the record of how it got there: which decisions were taken, which\n  alternatives were tried and rejected, what was deferred and why, what an\n  earlier version said, and status lines such as \"shipped\" or \"open\".\n\nState the rule or the fact rather than the measurement or the history that led\nto it: \"no extension is known to use it\", not \"none of the 29 surveyed\nextensions uses it\"; \"renderer code gets no guarantee of Node\", not \"decided in\nthe API review\". The measurement, the history and the issue references belong\nin the pull request description and the issue, which are dated by nature.\nThose are working notes; documentation is for the reader who uses the thing\nnow, and needs only its current state.\n\nExisting documents still carry such references. Do not copy them as a pattern,\nand drop them from a passage you are rewriting anyway.\n\n## Build System\n\n### Commands\n\n```bash\npnpm build:di           # Generate DI registration files\npnpm build              # Build all packages\npnpm build:app:dir      # Build Electron app directory\npnpm start              # Start development app\npnpm test               # Run tests\n```\n\n### Clean Build\n\nThis project uses Turbo for caching build artifacts.\n\nWhen facing caching issues:\n\n```bash\nrm -rf .turbo packages/core/dist freelens/dist\npnpm build\n```\n\n## Runtime Environments in Type-Checking\n\nThe application runs code in two environments: **main** (Node, Electron) and\n**renderer** (a browser page). `pnpm type:check` checks the sources of\n`freelens/src` and `packages/core/src` once per environment, so that an API the\nenvironment does not have fails the check before it fails at runtime:\n\n| Program                   | Environment                     | Checks                                  |\n| ------------------------- | ------------------------------- | --------------------------------------- |\n| `tsconfig.typecheck.json` | DOM and Node                    | every file, tests and unclassified ones |\n| `tsconfig.main.json`      | Node, no DOM                    | main and common files                   |\n| `tsconfig.renderer.json`  | DOM, no Node                    | renderer and common files               |\n\nThe two environment programs extend `tsconfig.typecheck.json`, so they share\nits `paths`. `pnpm type:check:environments` runs them alone.\n\n### Which environment a file belongs to\n\nThe context segments in a file's path decide:\n\n- `main/` or `main-api/` anywhere in the path: the main program;\n- `renderer/` or `renderer-api/` anywhere in the path: the renderer program;\n- `common/` or `common-api/` with neither of the above: both programs. A main\n  or renderer segment wins over common, so `renderer/common/` is renderer code.\n\nContexts nest anywhere (`features/*/{main,renderer,common}`), and the\n`include` and `exclude` globs of the two configs express exactly this rule.\nPut new code under a context directory. A file whose path carries no context\nhas to be listed in the `include` of the config (or both configs, for common\ncode) of the process that loads it; the lists at the end of both `include`\narrays hold the existing ones. An unlisted one is checked by the combined\nprogram only, like `extensions/extension-api.ts`, which bundles the types of\nall three extension API namespaces on purpose.\n\nTests and test support (`*.test.ts(x)`, `__tests__/`, `test-utils/`,\n`*.global-override-for-injectable.ts`, `getDiForUnitTesting`, …) are kept out\nof both programs, because Vitest runs them with DOM and Node alike.\n\nNo tsconfig declares the Vitest globals. TypeScript has no per-file globals,\nand tests share a program with the sources next to them, so declaring\n`describe` or `vi` for the tests would declare them for production code too.\nTest code imports what it uses instead:\n\n```ts\nimport { describe, expect, it, vi } from \"vitest\";\n```\n\n`globals: true` stays on in the Vitest configs, because React Testing Library\nregisters its automatic cleanup only when the hooks exist as globals; it has no\neffect on type checking. An override in `biome.jsonc` sets\n`noRestrictedImports` for every file on the test-only modules: `vitest`,\n`react-dom/test-utils`, `@testing-library/*` and the `act` named import of\n`react`. A second override lifts it for tests and test support, so production\ncode in any package fails `biome check` when it imports one of them. The React\nhelpers matter most, because nothing else catches them: they type-check, build\nand pass the unit tests, but `act` delegates to `React.act`, which the\nproduction build of React leaves out, so the call throws only in a packaged\napplication. A new kind of test-support path, or a new test-support package\nbuilt on Testing Library, needs adding to the second override.\n\nCommon code uses only what both environments have: `globalThis.crypto`,\n`TextEncoder`, `URL`, `AbortController`, `structuredClone`, timers. Write\n`globalThis.` when in doubt. The extension-side version of the same rule is in\nthe source-layout section of `docs/extensions/migrating-from-v1.md`.\n\n### How the check works\n\n`scripts/type-check-environments.mjs` runs both programs and counts only the\nerrors in a program's own files, the ones its `include` classifies. A program\nalso holds every file its files import, including the other environment's\nfiles and other packages, and their errors there say nothing about the\nenvironment rule; the combined program checks those files in full.\n\nFiles that failed the check when it was introduced are on the legacy lists in\n`scripts/type-check-environments/legacy.jsonc`: main or common files that need\nDOM, and renderer or common files that need Node, which the node-integrated\nrenderer still allows. Their errors are tolerated. **The lists may only\nshrink:** never add a file to make a new error pass. When a listed file stops\nfailing, the check fails until it is removed from its list.\n\n`scripts/type-check-environments/expected-failures/` proves that the programs\nstill reject what they should: every line there that must fail carries\n`@ts-expect-error`, so a program that lets it through reports an unused\ndirective. Its `main/`, `renderer/` and `common/` subdirectories fall into the\nprograms by the same rule as the sources.\n\nTwo things in the dependencies would otherwise defeat the programs silently;\nthe expected-failure files catch both if they come back:\n\n- A declaration file with `/// <reference types=\"node\" />`, and winston,\n  electron and undici all have one, loads `@types/node` into any program that\n  reaches it, whatever `types` says. The renderer program sets `typeRoots` to\n  `scripts/type-check-environments/renderer-type-roots/`, whose empty `node`\n  package absorbs those references.\n- A declaration file with `/// <reference lib=\"dom\" />` adds DOM to any program\n  that reaches it, whatever `lib` says. The main program reaches renderer code\n  through type imports, so the pnpm patch of `@xterm/xterm` removes that line\n  from its typings. A new dependency with the same line needs the same\n  treatment.\n\nDOM _type_ names such as `HTMLElement` still resolve in the main program,\nbecause `@types/react` declares empty stand-ins for them; values such as\n`document` and `window` do not.\n\n### The editor\n\nVS Code uses the root `tsconfig.json`, which has DOM and Node together, for\nevery file. The environment programs are a CI check the editor does not\nreflect: a Node global in renderer code shows no type error in the editor and\nfails `pnpm type:check`.\n\nBiome covers part of the gap while you type. An override in `biome.jsonc`\nturns on `noNodejsModules` for the `renderer/`, `renderer-api/`, `common/` and\n`common-api/` files of `freelens/src` and `packages/core/src`, classified by\nthe same path rule as the renderer program and with the same test files left\nout. It catches **imports** of Node builtins (`node:fs`, `path`, …), so the\nBiome extension flags them in the editor and `biome check` fails on them. It\ndoes not catch **Node globals** such as `Buffer`, `process`, `__dirname` or\n`NodeJS.*` types, and it does not look at the files that carry no context in\ntheir path; only `pnpm type:check` catches those.\n\nThe files that import a Node builtin today are exempted in a second override,\nwhich turns the rule off for them. Every one of them is also on the renderer\nlegacy list, and `scripts/type-check-environments.mjs` fails when an exempted\nfile is not, so the exemptions can only shrink with that list: remove a file\nfrom both when you move its Node import out.\n\nEvery path in the `includes` of a `biome.jsonc` override starts with `**/`,\nnegated ones included (`!**/packages/core/src/...`). Trunk Check, which is what\nruns Biome in CI, runs it from a sandbox outside the repository with\n`--config-path` pointing back at `biome.jsonc`, and there a pattern anchored at\nthe repository root matches no file, so the override silently does nothing.\nA plain `biome check` from the repository root matches both forms, so only\n`trunk check` shows the difference. `scripts/type-check-environments.mjs`\nchecks every path of every override and fails on one that is neither `**` nor\nstarts with `**/` or `!**/`.\n\n## Knip\n\n`pnpm knip:check` runs knip in two passes, both for dependencies. CI runs it\nafter `pnpm build`, so run a build first.\n\n- The development pass, `pnpm knip:development`, also reports **unused\n  files**: a module, barrel or stylesheet that no entry reaches. Stylesheets\n  count, because the `project` globs of the packages with styles include\n  `scss` and `css`, and knip follows both the side-effect imports in\n  TypeScript and `@use` in SCSS.\n- The production pass, `pnpm knip:production`, runs with `--production\n  --strict` over the entries marked with `!` in `knip.jsonc`, the code that\n  reaches the bundles. In it only `dependencies` count. It does not check\n  files: from the `!` entries alone, the test support and the development\n  scripts count as unused.\n\nWhen the file check reports a file, remove it rather than ignore it. Before\nyou do, check that nothing reaches it in a way knip cannot see, and that\n`pnpm type:check` and the tests still pass without it. A file that is reached\nthat way, through a config path built at runtime, a `tsconfig.json` `include`\nor a `meta.load-css()`, gets an entry in `knip.jsonc` instead, with a comment\nsaying how it is reached. A `register-injectables.ts` that nothing imports is\nthe generator's output and gets an ignore: removing it only makes\n`pnpm build:di` write it again.\n\nBoth passes run with `--no-gitignore`, because the dependency check reads the\nbundled `freelens/static/build/main.js` to find the packages the main bundle\nleaves external. The file check therefore also sees build output and local\nfiles; `knip.jsonc` ignores the build output nothing imports and the local\nartifacts of the MCP servers and of coverage. One config serves both passes,\nso `--no-config-hints` hides the hints about entries only one pass needs.\n\nThe check leaves out unused exports and types, and knip cannot report the\nunused classes inside a stylesheet.\n\n## Dependency Injection System\n\nThis project uses `@ogre-tools/injectable` for dependency injection with an **explicit registration system** that replaces the old webpack-based auto-registration. All injectable registrations are generated by `pnpm build:di`.\n\n### Registration Hierarchy\n\nThe system has three levels of registration files:\n\n1. **Leaf registration files** - Register individual injectables\n   - Example: `features/preferences/renderer/close-preferences/register-injectables.ts`\n   - Pattern: Import injectable definitions and call `di.register()`\n   - Each call wrapped in try-catch for idempotency\n\n2. **Aggregator registration files** - Register subdirectories\n   - Example: `features/preferences/renderer/register-injectables.ts`\n   - Pattern: Import and call `registerXxxInjectables(di)` from subdirectories\n   - Each call wrapped in try-catch to handle duplicates\n\n3. **Root registration files** - Entry points per process\n   - `register-injectables-main.ts` - Main process\n   - `register-injectables-renderer.ts` - Renderer process\n   - Called during DI container initialization\n\n### Directory Patterns\n\n#### Shared Aggregators\n\nDirectories with `register-injectables.ts` that aggregate subdirectories:\n\n```text\nfeatures/vars/\n├── register-injectables.ts     ← Shared aggregator (calls common/)\n├── common/\n│   └── register-injectables.ts\n└── build-version/\n    ├── main/register-injectables.ts      ← Process-specific (NOT aggregated)\n    └── renderer/register-injectables.ts  ← Process-specific (NOT aggregated)\n```\n\n**Key insight:** Shared aggregators only handle **shared** subdirectories (like `common/`). They do NOT aggregate **process-specific** subdirectories (`main/`, `renderer/`).\n\n#### Process-Specific Paths\n\nPaths containing `/main/` or `/renderer/` are process-specific and must be imported directly:\n\n- ✅ Include: `features/vars/build-version/main/register-injectables`\n- ❌ Exclude: `features/vars/common/register-injectables` (handled by parent aggregator)\n\n### When to Re-run Generation\n\nRun `pnpm build:di` when:\n\n- Adding new injectable files\n- Moving injectable files\n- Renaming injectable files\n- Changing directory structure\n- Modifying generation script\n\nThe build process automatically runs this, but you can run it manually to verify changes.\n\n### Bundled Binary Versions\n\nThe versions of the bundled `freelens-k8s-proxy`, `kubectl` and `helm` live in\nthe `config` block of `freelens/package.json`, and their exact digests are\npinned in `freelens/binaries.lock.json`. The build reads the expected checksum\nfrom that lock rather than from the vendor, so **a version bump without\nregenerating the lock fails the build**:\n\n```sh\npnpm update-binaries-lock\n```\n\nThe generator downloads all eighteen artifacts (three tools, three platforms,\ntwo architectures), checks each against its publisher's signature — GitHub build\nprovenance for freelens-k8s-proxy, PGP for helm, keyless cosign for kubectl —\nand only then writes the lock. `cosign` comes from mise (`mise install`), and\n`GITHUB_TOKEN` should be set unless you want to share 60 unauthenticated API\ncalls per hour with the rest of your IP. Use `--only <tool>` to refresh a single\ntool while iterating.\n\nhelm is downloaded as a tarball, so its `sha256` pins the archive and a second\ndigest, `binarySha256`, pins the binary extracted from it. The build hashes\nevery file already in `freelens/binaries/` against the lock on each run and\ndownloads it again on a mismatch; it keeps no record of what it verified\nbefore. That is what makes the directory safe to restore from a CI cache:\nwhoever could write a binary into the cache could write such a record too.\nFor the same reason the binaries are not an output of a cached Turbo task: the\nTurbo cache would restore them without the check. `build:binaries` runs\nuncached on every build instead, which costs only the hashing when the\nbinaries are in place.\n\n`.github/workflows/binaries-lock-check.yaml` enforces both that the lock is\ncurrent and that no digest changed while its version stood still. On a\nRenovate branch a stale lock does not fail the check: Renovate bumps the\nversion but cannot run the generator, so the workflow regenerates the lock,\nchecks it for replaced artifacts, and commits it to the branch with `GH_TOKEN`,\nwhich starts the checks again on the new commit.\n\n### Downloaded kubectl Versions\n\nThe bundled kubectl is not the only one the application runs: a cluster whose\nminor version differs gets a version-matched kubectl downloaded at runtime. The\nmap of which patch to fetch per minor lives in\n`packages/kubectl-versions/build/versions.json`, and the digest of every\nartifact that map can produce is pinned in\n`packages/kubectl-versions/build/checksums.json`, keyed by version and then by\n`${platform}/${arch}`.\n\n`Kubectl.downloadKubectl()` hashes what it downloaded and refuses anything that\ndoes not match its pin, and `ensureKubectl()` refuses to download at all when\nthere is no pin, falling back to the bundled binary. **A version added to the\nmap without a pin therefore never gets downloaded**, so the two files are\nregenerated together:\n\n```sh\npnpm --filter @freelensapp/kubectl-versions compute-versions\npnpm update-kubectl-checksums\n```\n\nThe generator reads `dl.k8s.io` only, never a mirror — pinning bytes from a\nmirror would let a compromised mirror bless its own digest. It skips versions\nalready present, which makes a run incremental and an existing pin immutable,\nand it verifies each download against both the published `.sha256` and the\nkeyless cosign signature before recording it. `cosign` comes from mise\n(`mise install`).\n\nBoth files start at 1.22, the oldest line Kubernetes publishes a signature for,\nand coverage is not uniform below that floor's neighbours: v1.22.17 has no\n`windows/arm64` build, so the generator logs an unpublished variant and carries\non rather than failing. `.github/workflows/kubectl-checksums-check.yaml`\nverifies added pins and asserts that no existing digest changed.\n\n### Development Tools (mise)\n\nThe development tools (`cosign`, `node`, `yq`) are declared in `mise.toml` and\npinned with their checksums in `mise.lock`. The lock uses lockfile format\nversion 3 (`lockfile_version = 3`), which **needs mise 2026.9.16 or newer**: an\nolder mise rejects the lock, so `mise install` fails until mise is upgraded.\n\nAfter changing a version in `mise.toml`, regenerate the lock with `mise lock`,\nwhich refreshes every tool on every platform in the file. `mise install`\nre-locks only the platform it runs on and leaves the others stale.\n\n## Common Development Tasks\n\n### Adding a New Feature\n\n1. Create feature directory under `packages/core/src/features/`\n2. Organize by concern: `common/`, `main/`, `renderer/`\n3. Create injectable files with `.injectable.ts` suffix\n4. Run `pnpm build:di` to generate registration files\n5. Write tests alongside implementation\n\n### Debugging the Application\n\n**Main Process:**\n- Logs in terminal where `pnpm start` was run\n- Use `console.log()` or proper logger\n\n**Renderer Process:**\n- Open DevTools in the app\n- Check Console tab for errors and logs\n- Use React DevTools for component inspection\n- `pnpm dev` also exposes a Chrome DevTools Protocol endpoint on port 9223\n  (`--remoteDebuggingPort`). Note that each cluster's UI renders in a\n  cross-origin `<clusterId>.renderer.freelens.app` iframe, so inspecting or\n  automating cluster views requires a frame-aware CDP client — see the\n  AI-agent inspection notes in DEVELOPMENT.md.\n\n**Common Errors:**\n- `Tried to register same injectable multiple times` - See DI section above\n- `Tried to inject non-registered injectable` - Check registration files were\n  generated. In a unit test, a newly added `*.injectable.ts` can report this\n  even when the file exists and `pnpm build:di` ran: `getDiForUnitTesting`\n  registers through `import.meta.glob(..., { eager: true })`, and\n  `node_modules/.vitest-cache` keeps the glob expanded over the files that\n  existed when it was first cached. Clear it (`rm -rf node_modules/.vitest-cache`)\n  and re-run.\n- Permission errors on macOS - Expected during development\n\n### Working with the bundler (electron-vite)\n\nThe project bundles with electron-vite (Vite + Rollup); the legacy Webpack\nlayer was removed in #2118.\n\n- `freelens/electron.vite.config.ts` - main/renderer build and dev-server config\n- `pnpm dev` runs `electron-vite dev` with Vite HMR; renderer source changes\n  hot-reload, main-process changes rebuild and relaunch (via `--watch`)\n- Changes to generated files (e.g. DI registration) require a full rebuild\n\n**Cache issues:** Delete the build output and rebuild\n(`rm -rf .turbo packages/core/dist freelens/dist`)\n\n### The Electron binary\n\n`pnpm install` leaves the `electron` package without its runtime binary. The\npackage has no `postinstall` script, so `electron: true` in `allowBuilds` has\nnothing to run; it downloads the binary lazily instead, when\n`require(\"electron\")` or its `electron` bin finds `path.txt` missing.\nelectron-vite does not go through either: it reads\n`node_modules/electron/path.txt` itself and throws `Electron uninstall` when\nthe file is absent, so `electron-vite dev` alone never triggers the download.\n\nThe `predev` script of `freelens/package.json` therefore runs the package's\n`install-electron` bin (`electron/install.js`) before `electron-vite dev`.\n`install.js` exits at once when the binary of the installed version is\nalready in place, and otherwise downloads it, verifies it against the\npackage's `checksums.json` and writes `path.txt`. pnpm runs `pre` scripts for\n`pnpm run dev`, both inside `freelens/` and through the root `turbo run dev`,\nwhich invokes `pnpm run dev` in the package.\n\nThe `dev` script is for local development only. CI does not use it: the\nworkflows that need the binary run `electron/install.js` explicitly, as a\nseparate step, before tests or the build.\n\n## Troubleshooting Patterns\n\n### Changes Not Appearing\n\n1. Check if file is in ignored directory (`dist/`, `node_modules/`)\n2. Clear the build output: `rm -rf .turbo packages/core/dist freelens/dist`\n3. Full rebuild: `pnpm build`\n4. Restart application: `pnpm start`\n\n### Build Failures\n\n1. Check for TypeScript errors: `pnpm type:check` (see \"Runtime Environments in\n   Type-Checking\" when the main or renderer program fails)\n2. Check for linting errors: `pnpm lint`\n3. Verify dependencies: `pnpm install`\n4. Check Node.js version matches `.nvmrc`\n\n### Runtime Errors\n\n1. Check dev console (renderer) or terminal (main)\n2. Look for stack traces with file:line numbers\n3. Verify all dependencies are registered (DI system)\n4. Check for circular dependencies\n\n## Architecture Decisions\n\n### Electron Multi-Process\n\n- **Main process** - Node.js environment, system access\n- **Renderer process** - Chromium browser, UI\n- **IPC** - Communication between processes\n\n### Feature Organization\n\nFeatures are self-contained modules with:\n- Domain logic\n- UI components\n- State management\n- Injectable definitions\n\n### Monorepo Structure\n\nUses pnpm workspaces for:\n- Shared code reuse\n- Faster builds\n- Type safety across packages\n\n## Styling\n\nFreelens carries four styling systems (theme CSS custom properties, global\nplain SCSS, CSS Modules, and Tailwind v4). Which one to use is not a matter of\ntaste — each has a defined role. Before adding or changing any stylesheet or\n`className`, read [`docs/styling.md`](./docs/styling.md). In short:\n\n- **Theme values** (colors, fonts): CSS custom properties from the TS theme\n  system (`var(--…)`) — the single contract every other system reads.\n- **Shared components** (`packages/ui-components`) and anything an extension\n  may restyle: global PascalCase class + plain SCSS + `var(--…)`. No Tailwind\n  (its JIT only scans core TSX), no CSS Modules (the class names are public\n  API).\n- **Core single components / full views**: CSS Modules (`*.module.scss`).\n- **Local layout inside core-only TSX**: Tailwind utilities. The legacy\n  `flexbox.scss` utilities have been removed — do not reintroduce them.\n- **Extensions**: see the styling section of\n  [`docs/extensions/migrating-from-v1.md`](./docs/extensions/migrating-from-v1.md).\n\n## Extension API\n\nThe extension specification lives in three documents, and which one to read\ndepends on the question:\n\n- [`docs/extensions/api.md`](./docs/extensions/api.md) — the **normative\n  contracts**. Each states the guarantee, the stable surface and the failure\n  mode. Read this before changing anything under `packages/extensions/` or\n  `packages/core/src/extensions/`.\n- [`docs/extensions/binaries.md`](./docs/extensions/binaries.md) — what an extension\n  may **ship and execute** besides JavaScript, and what the host does with it.\n- [`docs/extensions/migrating-from-v1.md`](./docs/extensions/migrating-from-v1.md) — the\n  author-facing **porting guide** from v1.\n\nThe agent skills of freelensapp/freelens-example-extension,\n`create-freelens-extension` and `port-freelens-extension-to-v2`, link to these\ndocuments on `main` and cite their sections by name. So does the template of\nthe v2 migration issue that a port copies,\n`skills/port-freelens-extension-to-v2/references/migration-issue.md`, except\nthat its links are pinned to a commit of this repository. Renaming or removing\none of the sections below therefore needs a matching change to the `SKILL.md`\nfiles under `skills/` in that repository, and to that template when its pin\nmoves to a commit with the change:\n\n- in `api.md`, the contracts C1 to C15 by number as a range, and C3\n  (host-provided singletons), C6 (registration), C9 (routing), C10 (styling\n  and CSS), C12 (HTTP) and C15 (the host's kubectl, helm and terminal\n  environment) on their own;\n- in `migrating-from-v1.md`, these headings:\n  - \"Step one: bump `engines.freelens`\"\n  - \"`package.json` for an extension\"\n  - \"Source layout: one tsconfig per runtime environment\"\n  - \"MobX 7 and mobx-react 10 (standard decorators only)\"\n  - \"Registering things: declarative fields\"\n  - \"Reaching a catalog cluster\"\n  - \"v1→v2 rename table\"\n  - \"Node and Electron in the renderer\"\n  - \"Styling and CSS\"\n  - \"The development loop\"\n  - \"Checklist\", and the two items at its end that it marks as failing\n    silently;\n- `binaries.md` as a whole document, by its file name;\n- in this file, the heading \"Modifying GitHub Actions Workflows\", which the\n  template cites.\n\nThree traps worth carrying without looking them up. The API surface is only what\nthe `Common` / `Main` / `Renderer` namespaces re-export — every other\n`@freelensapp/*` package is private and inlined into the published declaration,\nso a symbol that is not re-exported is unreachable by any means. And the host\nmust be the single instance of React, mobx and monaco; a second\ncopy of mobx fails **silently**, so changes there need an identity assertion\nrather than a passing test suite.\n\nThe third: the published declaration is not the source. `rolldown-plugin-dts`\nturns each module behind a namespace into a `declare namespace` that\nre-exports its members, and it drops the `type` modifier on the way. A **class\nre-exported type-only**, with `export type { C }` or `export type { C } from\n\"…\"`, is therefore declared as a value too, so `new C(…)` and `x instanceof C`\ncompile against the declaration and throw in the extension. Use a type alias\ninstead, `export type C<T> = import(\"…\").C<T>`, carrying the class's type\nparameters with their constraints and defaults.\n\nTwo guards catch a regression.\n`packages/core/src/extensions/__tests__/extension-api-declared-values.test.ts`\nwalks the built declaration with the TypeScript 7 checker\n(`typescript/unstable/sync`) and fails on every value it declares that the\nruntime namespace object does not have. The fixture extension's\n`packages/fixture-extension/src/common/contract-types.ts` names the\ntype-and-value pairs of `K8sApi`, `type X` and `const X` of the same name, as\ntypes, so its type check fails if one loses its type meaning in the bundle.\n\nThe bundle also depends on `rolldown-plugin-dts` 0.28.8 or newer, which\ntree-shakes a namespace import whose members a declaration names only by\nqualified name, such as `import * as utilities` in `common-api/utils.ts`. An\nolder version keeps every member of the module in the bundle. That includes\nthe Node-bound members `Common.Util` leaves out, with their `node:` imports.\n`build:dist` of `@freelensapp/extensions` fails when the bundle imports a Node\nbuiltin or references Node's types, and names that tree-shaking as the likely\ncause, so a regression in the plugin fails the build rather than reaching an\nextension.\n\n## Best Practices\n\n1. **Always regenerate DI files** after adding/moving injectables\n2. **Full rebuild** when in doubt about cached state\n3. **Check both processes** when debugging (main + renderer)\n4. **Use semantic search** to find examples in codebase\n5. **Follow existing patterns** - grep for similar implementations\n6. **Test changes** before committing\n7. **Run validation after file changes (especially before commit):** run `trunk check` (or `pnpm trunk check` if `trunk` is not installed locally)\n8. **For main project TypeScript and HTML files:** run `pnpm biome check` (`--write` to apply the fixes). Biome is not a dependency of the project: the `biome` script of the root `package.json` runs the pinned version through `pnpm dlx`. A bare `biome` or `pnpm exec biome` runs whatever `biome` is on `PATH`, such as a Homebrew one, whose version may format differently and rewrite code the change does not touch.\n9. **For other file types:** use `trunk check` (or `pnpm trunk check` if `trunk` is not installed locally)\n10. **Do not use Antropic Fable for coding tasks** — Fable may be used only for planning,\n    analysis, and thinking through problems. When writing or editing code,\n    use standard editing tools instead.\n\n## Local Agent: Triggering the GitHub Agent\n\nThese rules apply to an agent running on a developer machine (a local Claude\nCode session), not to the workflow agent. The local agent shares the repository\nwith the CI agent defined in `.github/workflows/claude.yaml`, and every comment\nit writes on GitHub is a potential trigger for it.\n\n### How the trigger works\n\n`claude.yaml` starts a run when the body of a **newly created** comment (issue\ncomment or PR review comment), a **newly opened** issue (body or title), or a\n**submitted** PR review contains the string `@claude`, and its author has\nwrite access to the repository (the admin, maintain or write role). The\nworkflow condition pre-filters on OWNER, MEMBER or COLLABORATOR, which does not\nimply write access, and the first step of the run checks the actual\npermission; a run triggered by anyone else fails there. The check is a plain\n`contains(github.event.comment.body, '@claude')` substring test, so the string\nfires the workflow wherever it appears — including inside a code span, a fenced\nblock, a quoted line, or a URL. Markdown formatting is not an escape.\n\nThe trigger text may also carry `[model:<alias>]`, `[effort:<level>]` and\n`[runs-on:<alias>]` markers, which select the model, the reasoning effort and\nthe runner for that run (see the `parse` job for the accepted aliases). They are\nonly read from the triggering text.\n\nThe default model is `claude-opus-5-5[1m]` (Opus 5.5 with the 1M-token\ncontext) and it runs at `high` effort. Naming a model explicitly drops that\ndefault: the run then uses the CLI default effort unless `[effort:...]` also\nsays otherwise. Accepted levels are `low`, `medium`, `high`, `xhigh` and\n`max`; anything else is ignored with a note in the job log.\n\n### Rules for the local agent\n\n1. **Write the handle only to start a run.** Ask the user before triggering: a\n   run is a 120-minute CI job on the repository, so it is the user's call, not\n   an implementation detail.\n2. **Escape the handle when merely referring to it.** In issue bodies, PR\n   descriptions, review notes, commit messages and documentation, write\n   `@<!-- -->claude` (displays as the handle, but the raw body does not contain\n   the literal string, so `contains()` does not match) or describe it in prose\n   as \"the Claude handle\". This is what keeps a plan or a bug report that\n   documents the trigger from firing it.\n3. **Editing never triggers.** The workflow subscribes only to `created`,\n   `opened` and `submitted` events — not `edited`. So updating a comment, an\n   issue body or a PR description is always safe, even when the text already\n   contains a real trigger, and conversely editing a comment to add the handle\n   does **not** start a run: a new comment is required.\n4. **One trigger per task.** Do not repeat the handle in follow-up comments\n   while a run is in flight; each occurrence starts another concurrent job.\n5. **Push first.** The workflow checks out the remote ref (the PR head, or the\n   default branch for issues), so anything not pushed is invisible to it.\n\n## GitHub Actions (Claude Code Action) Rules\n\nWhen operating via the `claude.yaml` workflow (i.e., invoked from a PR comment,\nissue, or review), follow these rules:\n\n### Code Review\n\nWhen reviewing code and proposing fixes:\n\n1. **Show the diff first** — present every proposed change as a unified diff\n   block using the `diff` language tag:\n\n   ```diff\n   --- a/path/to/file.ts\n   +++ b/path/to/file.ts\n   @@ -10,7 +10,7 @@\n    const oldLine = \"before\";\n   -const changedLine = \"after\";\n   +const changedLine = \"the fix\";\n    const unchangedLine = \"same\";\n   ```\n\n   You can generate this from the terminal with:\n   ```bash\n   git diff -u -- path/to/file\n   ```\n\n   If the change spans multiple files, group them under a single commit\n   subject and show each file's diff sequentially.\n\n2. **Propose a commit subject first** — before any code change, output a\n   single line with the proposed commit subject:\n\n   ```text\n   **Proposed commit:** <short description>\n   ```\n\n   Do **not** use Conventional Commits prefixes (e.g. `fix:`, `feat:`,\n   `chore:`, `refactor:`, `docs:`, `test:`, `ci:`). This project prefers\n   plain, descriptive commit messages and PR titles without any prefix.\n\n   Wait for the user to confirm (or adjust) the subject before applying the\n   change.\n\n3. **Comment style:**\n   - Keep review comments concise and actionable\n   - Reference specific lines (file + line number) when pointing out issues\n   - Offer a concrete fix suggestion rather than just flagging a problem\n   - Do **not** use emoji in any Markdown, comments, commit messages, or\n     PR descriptions. The only exception is emoji that already appears\n     inside code strings (e.g. application logs, user-facing messages).\n   - Use GitHub's `suggestion` block for small targeted fixes so the PR\n     author can accept the change with a single click:\n\n     ````suggestion\n     <same unified-diff format as shown above>\n     ````\n\n   - For larger multi-file changes, use `diff -u` blocks in a regular\n     comment instead, with the proposed commit subject shown first\n\n### Making Changes to a PR\n\nWhen asked to implement a change on a PR:\n\n1. Propose the commit subject (as above)\n2. Describe what will change and why\n3. After confirmation, apply the changes with commits on the PR branch\n4. **One commit per fix** — when a review surfaces more than one issue or\n   the plan includes more than one fix, apply and commit each fix\n   separately. Do not batch multiple independent fixes into a single\n   commit. This keeps the history bisectable and makes each change easy\n   to revert individually.\n\n### Pushing After Every Commit\n\nThe GitHub Actions job running Claude has a total timeout of 120 minutes.\nWhen the session times out, any commits that exist only in the runner's\nlocal checkout are lost. To make the work resumable in a follow-up session:\n\n1. **Push to the remote branch immediately after every commit.** Do not\n   accumulate multiple local commits before pushing — commit, push, then\n   move on to the next change.\n2. This pairs with the \"one commit per fix\" rule above: each completed fix\n   should land on the remote branch as soon as it is committed, so a\n   timed-out session can be resumed from the last pushed commit instead of\n   starting over.\n3. **Run every command in the foreground.** The workflow runs Claude\n   headless: the session ends as soon as the agent ends its turn, and\n   nothing wakes it up when a background command finishes. A build, a\n   test run or `trunk check` started in the background and then waited on\n   is killed with the job, together with every uncommitted change. Give\n   long commands a foreground timeout (up to ten minutes) instead, and\n   commit and push what is done before starting a long validation.\n\n### Force-Pushing a Rewritten Branch\n\nWhen you are asked to rebase a pull request branch, or to rewrite its\nhistory in another way (amend, squash, drop a commit), push the result with:\n\n```bash\ngit push --force-with-lease origin HEAD\n```\n\nThe push wrapper the action names in its instructions, `git-push.sh`, accepts\nno flags, so it cannot do this; `git` itself is allowed in this workflow.\nDo not fall back to merging `main` into the branch instead: a merge commit is\nnot what was asked for.\n\nForce-push only the pull request branch the run was invoked on, and only when\nthe request calls for a rewrite. Never force-push `main` or any other branch,\nand never rewrite a history you were not asked to.\n\n### Modifying GitHub Actions Workflows\n\nClaude cannot push changes to files under `.github/workflows/` directly,\nbecause the GitHub token used by the action lacks the `workflows` permission.\nAny patch to a workflow file MUST therefore be delivered as a new, complete\nfile under the `github-workflow-fix/` directory instead of editing the file in\nplace:\n\n1. Write the full, final contents of the workflow to\n   `github-workflow-fix/<workflow-file-name>` (e.g.\n   `github-workflow-fix/claude.yaml`). Do **not** edit the original file under\n   `.github/workflows/`.\n2. Make it a **complete** file — the entire workflow as it should look after\n   the change, not just a diff or fragment — so it can be copied verbatim.\n3. Commit and open the PR as usual. In the PR description, clearly note that\n   the file is a proposed workflow change and that a maintainer must move it\n   from `github-workflow-fix/` to `.github/workflows/` manually.\n\nThis lets the PR be created successfully while leaving the actual workflow\nchange for a human to apply.\n\n### Branch Naming\n\n**Work on the branch the workflow put you on.** Do not rename it, and do not\nmove the work to a better-named branch.\n\n`claude-code-action` creates the branch itself, as\n`claude/issue-<number>-<date>-<time>`, and the workflow passes it no name to\nuse instead. Its comment header — the branch link and the \"Create PR\" link —\nis written from that name. So an agent that moves to a different branch leaves\nthe header pointing at an abandoned one, leaves a stray branch behind, and\nspends part of its run on a rename instead of the task. This guide used to\nrequire a readable name and forbid the timestamp, which produced exactly that\nevery time.\n\nIf you are creating a branch yourself, with no workflow-provided one, use\n`claude/<short-slug>`.\n\nThe branch name is not worth managing: it lives for a few hours and the pull\nrequest is what anyone refers to afterwards.\n\n### PR Title Conventions\n\nWhen creating a PR, use the following title conventions:\n\n- **Agent-related changes** — PRs whose changes are strictly related to coding\n  agent configuration (e.g. `AGENTS.md`, `.github/workflows/claude.yaml`, or\n  other files that govern how Claude operates in this repository) MUST use\n  the prefix `Claude:` (followed by a space) in the title.\n\n  Examples:\n  - `Claude: Add rule for PR title conventions in AGENTS.md`\n  - `Claude: Update claude.yaml workflow permissions`\n\n- **All other PRs** — do **not** use any prefix (no `fix:`, `feat:`, `chore:`,\n  etc.). Use plain, descriptive titles.\n\n### Fork PRs: Review Only\n\nA PR from a fork (different owner than `freelensapp`) gets a review and\nnothing else: no commits, no pushes, no branches. Its code is untrusted, and\nthe head of a fork PR can change between the moment a maintainer looks at it\nand the moment the workflow checks it out, so nothing taken from the checkout\nmay reach `freelensapp/freelens`.\n\nWhen a fork PR needs changes, a maintainer first copies the exact commit they\nreviewed to a branch in this repository. From then on it is a\nsame-repository PR, which gets the full setup and the normal workflow. The\ncopy is made either locally (`gh pr checkout <N>`, then push the branch) or\nby the Claude Task workflow, following \"Copying a Fork PR\" below.\n\n### Copying a Fork PR\n\nThis applies to a Claude Task run whose prompt asks to copy a fork PR and\nnames the PR number and the full commit SHA to copy. It is a git-only task:\ndo not check out, read, build or run any of the PR's files, and do not\ndescribe its changes, because they are untrusted input.\n\n1. `git fetch origin refs/pull/<N>/head`.\n2. Verify that `FETCH_HEAD` equals the given SHA. If it does not, or no full\n   SHA was given, stop and report the actual head without pushing anything.\n3. `git push origin <sha>:refs/heads/claude/pr-<N>`.\n4. Open a PR from `claude/pr-<N>` to `main`. It MUST use the **exact same\n   title** as the original PR, copied verbatim with no prefix, and its body\n   is `Copy of #<N> at <sha>.` followed by the usual footer.\n5. Comment on the original PR with a link to the new one.\n\n### Closing PRs\n\nClaude may only close a PR when ALL of the following are true:\n\n1. The PR was created by Claude from a `claude/` branch, OR the PR is the\n   original fork PR that a copy supersedes (see \"Copying a Fork PR\" above).\n2. The close reason is explicitly explained in a comment on the PR.\n\nClaude MUST NOT close any PR that does not meet these conditions — even if\nasked. Instead, explain to the requester why the PR cannot be closed\nautomatically and ask a human maintainer to close it manually.\n\n### Model Information in Comments\n\nWhen operating via the GitHub Actions workflow, always include the model you are\nrunning on in the footer of your GitHub comment and in the PR description when\ncreating a pull request, alongside the job run link.\nYour system environment context states the model name explicitly (e.g.\n\"You are powered by the model named Sonnet 4.6. The exact model ID is\nclaude-sonnet-4-6.\"). Use the exact model ID from that statement.\n\nFormat the footer line as:\n\n```text\n[View job run](...) | Model: `claude-sonnet-4-6`\n```\n\nIn a PR description, append the model information at the end of the body:\n\n```text\n| Model: `claude-sonnet-4-6`\n```\n\nIf the system context does not provide a model ID, omit the model field rather\nthan guessing.\n\n### Development Environment\n\nThe GitHub Actions runner has a full Node.js + pnpm environment available, and\nthe workflow attempts to install the dependencies (`pnpm install`), the\n`trunk` CLI and mise, with the `cosign` and `yq` that `mise.lock` pins, before\nstarting Claude. The build step is skipped to save CI resources, but you can\nrun build commands when needed for advanced tasks (e.g. type-checking, running\ntests).\n\nEvery one of those setup steps is `continue-on-error`, so any of them may have\nfailed and left its tool or `node_modules` missing. Verify that what you need\nis actually there before relying on it, and never report a check as passing\nwhen it did not run — say that it was unavailable instead.\n\nThe `origin` remote is always `freelensapp/freelens`, for fork PRs too: their\ncommits are checked out through the pull ref.\n\nA PR from a fork runs in review mode, because its code is untrusted and the\njob holds write tokens. None of the setup above runs, and the tools that\nexecute the repository's code (`pnpm`, `node`, `npx`, `bash`, `trunk`,\n`mise`), edit files or commit and push are not available. Review the code by\nreading it, and say that no check ran. See \"Fork PRs: Review Only\" for how a\nfork PR that needs changes is handled.\n\nThe following CLI tools are explicitly allowed in the workflow:\n\n- `pnpm` (all subcommands) — for validation, formatting, and builds\n- `git` (all subcommands) — for viewing changes, creating branches,\n  committing, and pushing\n- `gh` (all subcommands) — for managing pull requests\n- `trunk` — for linting and formatting every non-TypeScript file type\n- `mise` — for regenerating `mise.lock` (`mise lock`) after a version bump in\n  `mi","packages/metrics/tsconfig.json":"# Metrics Skill\n\nPath: `packages/metrics/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/metrics/tsconfig.json)","packages/logger/package.json":"# Logger Skill\n\nPath: `packages/logger/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/logger/package.json)","packages/logger/README.md":"# logger Documentation\n\nPath: `packages/logger/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/logger/README.md)","packages/logger/tsconfig.json":"# Logger Skill\n\nPath: `packages/logger/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/logger/tsconfig.json)","packages/list-layout/package.json":"# List-layout Skill\n\nPath: `packages/list-layout/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/list-layout/package.json)","packages/list-layout/tsconfig.json":"# List-layout Skill\n\nPath: `packages/list-layout/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/list-layout/tsconfig.json)","packages/kubectl-versions/package.json":"# Kubectl-versions Skill\n\nPath: `packages/kubectl-versions/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/package.json)","packages/kubectl-versions/README.md":"# kubectl-versions Documentation\n\nPath: `packages/kubectl-versions/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/README.md)","packages/kubectl-versions/tsconfig.json":"# Kubectl-versions Skill\n\nPath: `packages/kubectl-versions/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/tsconfig.json)","packages/kube-object/package.json":"# Kube-object Skill\n\nPath: `packages/kube-object/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kube-object/package.json)","packages/kube-object/tsconfig.json":"# Kube-object Skill\n\nPath: `packages/kube-object/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kube-object/tsconfig.json)","packages/generate-tray-icons/package.json":"# Generate-tray-icons Skill\n\nPath: `packages/generate-tray-icons/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-tray-icons/package.json)","packages/generate-tray-icons/tsconfig.json":"# Generate-tray-icons Skill\n\nPath: `packages/generate-tray-icons/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-tray-icons/tsconfig.json)","packages/generate-license/package.json":"# Generate-license Skill\n\nPath: `packages/generate-license/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-license/package.json)","packages/generate-license/tsconfig.json":"# Generate-license Skill\n\nPath: `packages/generate-license/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-license/tsconfig.json)","packages/extensions/package.json":"# Extensions Skill\n\nPath: `packages/extensions/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/extensions/package.json)","packages/extensions/tsconfig.dts.json":"# Extensions Skill\n\nPath: `packages/extensions/tsconfig.dts.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/extensions/tsconfig.dts.json)","packages/extensions/tsconfig.json":"# Extensions Skill\n\nPath: `packages/extensions/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/extensions/tsconfig.json)","packages/ensure-binaries/package.json":"# Ensure-binaries Skill\n\nPath: `packages/ensure-binaries/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ensure-binaries/package.json)","packages/ensure-binaries/tsconfig.json":"# Ensure-binaries Skill\n\nPath: `packages/ensure-binaries/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ensure-binaries/tsconfig.json)","packages/core/package.json":"# Core Skill\n\nPath: `packages/core/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/core/package.json)","packages/core/tsconfig.json":"# Core Skill\n\nPath: `packages/core/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/core/tsconfig.json)","packages/cluster-sidebar/package.json":"# Cluster-sidebar Skill\n\nPath: `packages/cluster-sidebar/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-sidebar/package.json)","packages/cluster-sidebar/tsconfig.json":"# Cluster-sidebar Skill\n\nPath: `packages/cluster-sidebar/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-sidebar/tsconfig.json)","packages/cluster-settings/package.json":"# Cluster-settings Skill\n\nPath: `packages/cluster-settings/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-settings/package.json)","packages/cluster-settings/README.md":"# cluster-settings Documentation\n\nPath: `packages/cluster-settings/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-settings/README.md)","packages/cluster-settings/tsconfig.json":"# Cluster-settings Skill\n\nPath: `packages/cluster-settings/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-settings/tsconfig.json)","packages/utility-features/utilities/package.json":"# Utilities Skill\n\nPath: `packages/utility-features/utilities/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/utilities/package.json)","packages/utility-features/utilities/README.md":"# utilities Documentation\n\nPath: `packages/utility-features/utilities/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/utilities/README.md)","packages/utility-features/utilities/tsconfig.json":"# Utilities Skill\n\nPath: `packages/utility-features/utilities/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/utilities/tsconfig.json)","packages/utility-features/test-utils/package.json":"# Test-utils Skill\n\nPath: `packages/utility-features/test-utils/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/test-utils/package.json)","packages/utility-features/test-utils/README.md":"# test-utils Documentation\n\nPath: `packages/utility-features/test-utils/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/test-utils/README.md)","packages/utility-features/test-utils/tsconfig.json":"# Test-utils Skill\n\nPath: `packages/utility-features/test-utils/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/test-utils/tsconfig.json)","packages/utility-features/startable-stoppable/package.json":"# Startable-stoppable Skill\n\nPath: `packages/utility-features/startable-stoppable/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/startable-stoppable/package.json)","packages/utility-features/startable-stoppable/tsconfig.json":"# Startable-stoppable Skill\n\nPath: `packages/utility-features/startable-stoppable/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/startable-stoppable/tsconfig.json)","packages/utility-features/run-many/package.json":"# Run-many Skill\n\nPath: `packages/utility-features/run-many/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/run-many/package.json)","packages/utility-features/run-many/README.md":"# run-many Documentation\n\nPath: `packages/utility-features/run-many/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/run-many/README.md)","packages/utility-features/run-many/tsconfig.json":"# Run-many Skill\n\nPath: `packages/utility-features/run-many/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/run-many/tsconfig.json)","packages/utility-features/react-testing-library-discovery/package.json":"# React-testing-library-discovery Skill\n\nPath: `packages/utility-features/react-testing-library-discovery/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/react-testing-library-discovery/package.json)","packages/utility-features/react-testing-library-discovery/tsconfig.json":"# React-testing-library-discovery Skill\n\nPath: `packages/utility-features/react-testing-library-discovery/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/react-testing-library-discovery/tsconfig.json)","packages/utility-features/kube-api-specifics/package.json":"# Kube-api-specifics Skill\n\nPath: `packages/utility-features/kube-api-specifics/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/kube-api-specifics/package.json)","packages/utility-features/kube-api-specifics/tsconfig.json":"# Kube-api-specifics Skill\n\nPath: `packages/utility-features/kube-api-specifics/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/kube-api-specifics/tsconfig.json)","packages/utility-features/kube-api/package.json":"# Kube-api Skill\n\nPath: `packages/utility-features/kube-api/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/kube-api/package.json)","packages/utility-features/kube-api/tsconfig.json":"# Kube-api Skill\n\nPath: `packages/utility-features/kube-api/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/kube-api/tsconfig.json)","packages/utility-features/json-api/package.json":"# Json-api Skill\n\nPath: `packages/utility-features/json-api/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/json-api/package.json)","packages/utility-features/json-api/tsconfig.json":"# Json-api Skill\n\nPath: `packages/utility-features/json-api/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/json-api/tsconfig.json)","packages/utility-features/event-emitter/package.json":"# Event-emitter Skill\n\nPath: `packages/utility-features/event-emitter/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/event-emitter/package.json)","packages/utility-features/event-emitter/tsconfig.json":"# Event-emitter Skill\n\nPath: `packages/utility-features/event-emitter/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/event-emitter/tsconfig.json)","packages/ui-components/tooltip/package.json":"# Tooltip Skill\n\nPath: `packages/ui-components/tooltip/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/tooltip/package.json)","packages/ui-components/tooltip/README.md":"# tooltip Documentation\n\nPath: `packages/ui-components/tooltip/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/tooltip/README.md)","packages/ui-components/tooltip/tsconfig.json":"# Tooltip Skill\n\nPath: `packages/ui-components/tooltip/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/tooltip/tsconfig.json)","packages/ui-components/spinner/package.json":"# Spinner Skill\n\nPath: `packages/ui-components/spinner/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/spinner/package.json)","packages/ui-components/spinner/README.md":"# spinner Documentation\n\nPath: `packages/ui-components/spinner/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/spinner/README.md)","packages/ui-components/spinner/tsconfig.json":"# Spinner Skill\n\nPath: `packages/ui-components/spinner/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/spinner/tsconfig.json)","packages/ui-components/resizing-anchor/package.json":"# Resizing-anchor Skill\n\nPath: `packages/ui-components/resizing-anchor/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/resizing-anchor/package.json)","packages/ui-components/resizing-anchor/README.md":"# resizing-anchor Documentation\n\nPath: `packages/ui-components/resizing-anchor/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/resizing-anchor/README.md)","packages/ui-components/resizing-anchor/tsconfig.json":"# Resizing-anchor Skill\n\nPath: `packages/ui-components/resizing-anchor/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/resizing-anchor/tsconfig.json)","packages/ui-components/notifications/package.json":"# Notifications Skill\n\nPath: `packages/ui-components/notifications/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/notifications/package.json)","packages/ui-components/notifications/README.md":"# notifications Documentation\n\nPath: `packages/ui-components/notifications/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/notifications/README.md)","packages/ui-components/notifications/tsconfig.json":"# Notifications Skill\n\nPath: `packages/ui-components/notifications/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/notifications/tsconfig.json)","packages/ui-components/icon/package.json":"# Icon Skill\n\nPath: `packages/ui-components/icon/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/icon/package.json)","packages/ui-components/icon/README.md":"# icon Documentation\n\nPath: `packages/ui-components/icon/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/icon/README.md)","packages/ui-components/icon/tsconfig.json":"# Icon Skill\n\nPath: `packages/ui-components/icon/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/icon/tsconfig.json)","packages/ui-components/error-boundary/package.json":"# Error-boundary Skill\n\nPath: `packages/ui-components/error-boundary/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/error-boundary/package.json)","packages/ui-components/error-boundary/README.md":"# error-boundary Documentation\n\nPath: `packages/ui-components/error-boundary/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/error-boundary/README.md)","packages/ui-components/error-boundary/tsconfig.json":"# Error-boundary Skill\n\nPath: `packages/ui-components/error-boundary/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/error-boundary/tsconfig.json)","packages/ui-components/button/package.json":"# Button Skill\n\nPath: `packages/ui-components/button/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/button/package.json)","packages/ui-components/button/README.md":"# button Documentation\n\nPath: `packages/ui-components/button/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/button/README.md)","packages/ui-components/button/tsconfig.json":"# Button Skill\n\nPath: `packages/ui-components/button/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/button/tsconfig.json)","packages/ui-components/animate/package.json":"# Animate Skill\n\nPath: `packages/ui-components/animate/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/animate/package.json)","packages/ui-components/animate/README.md":"# animate Documentation\n\nPath: `packages/ui-components/animate/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/animate/README.md)","packages/ui-components/animate/tsconfig.json":"# Animate Skill\n\nPath: `packages/ui-components/animate/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/animate/tsconfig.json)","packages/technical-features/react-application/package.json":"# React-application Skill\n\nPath: `packages/technical-features/react-application/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/react-application/package.json)","packages/technical-features/react-application/README.md":"# react-application Documentation\n\nPath: `packages/technical-features/react-application/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/react-application/README.md)","packages/technical-features/react-application/tsconfig.json":"# React-application Skill\n\nPath: `packages/technical-features/react-application/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/react-application/tsconfig.json)","packages/technical-features/prometheus/package.json":"# Prometheus Skill\n\nPath: `packages/technical-features/prometheus/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/prometheus/package.json)","packages/technical-features/prometheus/tsconfig.json":"# Prometheus Skill\n\nPath: `packages/technical-features/prometheus/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/prometheus/tsconfig.json)","packages/technical-features/feature-core/package.json":"# Feature-core Skill\n\nPath: `packages/technical-features/feature-core/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/feature-core/package.json)","packages/technical-features/feature-core/README.md":"# feature-core Documentation\n\nPath: `packages/technical-features/feature-core/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/feature-core/README.md)","packages/technical-features/feature-core/tsconfig.json":"# Feature-core Skill\n\nPath: `packages/technical-features/feature-core/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/feature-core/tsconfig.json)","packages/resource-templates/templates/.yamlfmt.yaml":"# Templates Skill\n\nPath: `packages/resource-templates/templates/.yamlfmt.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/.yamlfmt.yaml)","packages/kubectl-versions/build/checksums.json":"# Build Skill\n\nPath: `packages/kubectl-versions/build/checksums.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/build/checksums.json)","packages/kubectl-versions/build/tsconfig.json":"# Build Skill\n\nPath: `packages/kubectl-versions/build/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/build/tsconfig.json)","packages/kubectl-versions/build/versions.json":"# Build Skill\n\nPath: `packages/kubectl-versions/build/versions.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/build/versions.json)","packages/infrastructure/typescript/package.json":"# Typescript Skill\n\nPath: `packages/infrastructure/typescript/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/infrastructure/typescript/package.json)","packages/infrastructure/typescript/README.md":"# typescript Documentation\n\nPath: `packages/infrastructure/typescript/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/infrastructure/typescript/README.md)","packages/business-features/keyboard-shortcuts/package.json":"# Keyboard-shortcuts Skill\n\nPath: `packages/business-features/keyboard-shortcuts/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/business-features/keyboard-shortcuts/package.json)","packages/business-features/keyboard-shortcuts/README.md":"# keyboard-shortcuts Documentation\n\nPath: `packages/business-features/keyboard-shortcuts/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/business-features/keyboard-shortcuts/README.md)","packages/business-features/keyboard-shortcuts/tsconfig.json":"# Keyboard-shortcuts Skill\n\nPath: `packages/business-features/keyboard-shortcuts/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/business-features/keyboard-shortcuts/tsconfig.json)","packages/technical-features/messaging/messaging-for-renderer/package.json":"# Messaging-for-renderer Skill\n\nPath: `packages/technical-features/messaging/messaging-for-renderer/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-for-renderer/package.json)","packages/technical-features/messaging/messaging-for-renderer/tsconfig.json":"# Messaging-for-renderer Skill\n\nPath: `packages/technical-features/messaging/messaging-for-renderer/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-for-renderer/tsconfig.json)","packages/technical-features/messaging/messaging-for-main/package.json":"# Messaging-for-main Skill\n\nPath: `packages/technical-features/messaging/messaging-for-main/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-for-main/package.json)","packages/technical-features/messaging/messaging-for-main/tsconfig.json":"# Messaging-for-main Skill\n\nPath: `packages/technical-features/messaging/messaging-for-main/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-for-main/tsconfig.json)","packages/technical-features/messaging/messaging-fake-bridge/package.json":"# Messaging-fake-bridge Skill\n\nPath: `packages/technical-features/messaging/messaging-fake-bridge/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-fake-bridge/package.json)","packages/technical-features/messaging/messaging-fake-bridge/tsconfig.json":"# Messaging-fake-bridge Skill\n\nPath: `packages/technical-features/messaging/messaging-fake-bridge/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-fake-bridge/tsconfig.json)","packages/technical-features/messaging/messaging/package.json":"# Messaging Skill\n\nPath: `packages/technical-features/messaging/messaging/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging/package.json)","packages/technical-features/messaging/messaging/tsconfig.json":"# Messaging Skill\n\nPath: `packages/technical-features/messaging/messaging/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging/tsconfig.json)","packages/technical-features/messaging/computed-channel/package.json":"# Computed-channel Skill\n\nPath: `packages/technical-features/messaging/computed-channel/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/computed-channel/package.json)","packages/technical-features/messaging/computed-channel/tsconfig.json":"# Computed-channel Skill\n\nPath: `packages/technical-features/messaging/computed-channel/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/computed-channel/tsconfig.json)","packages/technical-features/application/application-for-electron-main/package.json":"# Application-for-electron-main Skill\n\nPath: `packages/technical-features/application/application-for-electron-main/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application-for-electron-main/package.json)","packages/technical-features/application/application-for-electron-main/README.md":"# application-for-electron-main Documentation\n\nPath: `packages/technical-features/application/application-for-electron-main/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application-for-electron-main/README.md)","packages/technical-features/application/application-for-electron-main/tsconfig.json":"# Application-for-electron-main Skill\n\nPath: `packages/technical-features/application/application-for-electron-main/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application-for-electron-main/tsconfig.json)","packages/technical-features/application/application/package.json":"# Application Skill\n\nPath: `packages/technical-features/application/application/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application/package.json)","packages/technical-features/application/application/README.md":"# application Documentation\n\nPath: `packages/technical-features/application/application/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application/README.md)","packages/technical-features/application/application/tsconfig.json":"# Application Skill\n\nPath: `packages/technical-features/application/application/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application/tsconfig.json)","packages/resource-templates/templates/create-resource/ClusterRole.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/ClusterRole.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ClusterRole.yaml)","packages/resource-templates/templates/create-resource/ClusterRoleBinding.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/ClusterRoleBinding.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ClusterRoleBinding.yaml)","packages/resource-templates/templates/create-resource/ConfigMap.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/ConfigMap.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ConfigMap.yaml)","packages/resource-templates/templates/create-resource/CronJob.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/CronJob.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/CronJob.yaml)","packages/resource-templates/templates/create-resource/DaemonSet.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/DaemonSet.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/DaemonSet.yaml)","packages/resource-templates/templates/create-resource/Deployment.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Deployment.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Deployment.yaml)","packages/resource-templates/templates/create-resource/Ingress.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Ingress.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Ingress.yaml)","packages/resource-templates/templates/create-resource/Job.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Job.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Job.yaml)","packages/resource-templates/templates/create-resource/Namespace.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Namespace.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Namespace.yaml)","packages/resource-templates/templates/create-resource/NetworkPolicy.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/NetworkPolicy.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/NetworkPolicy.yaml)","packages/resource-templates/templates/create-resource/PersistentVolume.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/PersistentVolume.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/PersistentVolume.yaml)","packages/resource-templates/templates/create-resource/PersistentVolumeClaim.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/PersistentVolumeClaim.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/PersistentVolumeClaim.yaml)","packages/resource-templates/templates/create-resource/Pod.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Pod.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Pod.yaml)","packages/resource-templates/templates/create-resource/PriorityClass.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/PriorityClass.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/PriorityClass.yaml)","packages/resource-templates/templates/create-resource/ReplicaSet.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/ReplicaSet.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ReplicaSet.yaml)","packages/resource-templates/templates/create-resource/ReplicationController.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/ReplicationController.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ReplicationController.yaml)","packages/resource-templates/templates/create-resource/Role.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Role.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Role.yaml)","packages/resource-templates/templates/create-resource/RoleBinding.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/RoleBinding.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/RoleBinding.yaml)","packages/resource-templates/templates/create-resource/RuntimeClass.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/RuntimeClass.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/RuntimeClass.yaml)","packages/resource-templates/templates/create-resource/Secret.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Secret.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Secret.yaml)","packages/resource-templates/templates/create-resource/Service.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Service.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Service.yaml)","packages/resource-templates/templates/create-resource/StatefulSet.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/StatefulSet.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/StatefulSet.yaml)","packages/infrastructure/typescript/config/base.json":"# Config Skill\n\nPath: `packages/infrastructure/typescript/config/base.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/infrastructure/typescript/config/base.json)"},"files":{"packages/semver/tsconfig.json":"{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"dist/\",\n    \"rootDir\": \"src/\",\n    \"types\": [\"node\"]\n  },\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"node_modules\"]\n}\n","packages/routing/tsconfig.json":"{\n  \"extends\": \"@freelensapp/typescript/config/base.json\",\n  \"include\": [\"**/*.ts\", \"**/*.tsx\"]\n}\n","packages/semver/package.json":"{\n  \"name\": \"@freelensapp/semver\",\n  \"version\": \"2.0.0-0\",\n  \"private\": true,\n  \"description\": \"CLI over verkit package for picking parts of a version\",\n  \"homepage\": \"https://freelens.app\",\n  \"bugs\": {\n    \"url\": \"https://github.com/freelensapp/freelens/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/freelensapp/freelens.git\"\n  },\n  \"license\": \"MIT\",\n  \"author\": {\n    \"name\": \"Freelens Authors\",\n    \"email\": \"freelens@freelens.app\"\n  },\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"tsc --pretty --project .\",\n    \"build:dev\": \"tsc --pretty --project .\",\n    \"clean:dist\": \"pnpm dlx rimraf@6.1.3 dist\"\n  },\n  \"dependencies\": {\n    \"command-line-args\": \"catalog:\",\n    \"verkit\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@types/command-line-args\": \"catalog:\",\n    \"@types/node\": \"catalog:\",\n    \"typescript\": \"catalog:\"\n  }\n}\n","packages/routing/package.json":"{\n  \"name\": \"@freelensapp/routing\",\n  \"version\": \"2.0.0-0\",\n  \"private\": true,\n  \"description\": \"Highly extendable routing in the Freelens.\",\n  \"homepage\": \"https://freelens.app\",\n  \"bugs\": {\n    \"url\": \"https://github.com/freelensapp/freelens/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/freelensapp/freelens.git\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"author\": {\n    \"name\": \"Freelens Authors\",\n    \"email\": \"freelens@freelens.app\"\n  },\n  \"main\": \"./index.ts\",\n  \"types\": \"./index.ts\",\n  \"scripts\": {},\n  \"dependencies\": {\n    \"@freelensapp/feature-core\": \"workspace:^\",\n    \"@ogre-tools/fp\": \"catalog:\",\n    \"@ogre-tools/injectable\": \"catalog:\",\n    \"@ogre-tools/injectable-react\": \"catalog:\",\n    \"mobx\": \"catalog:\",\n    \"mobx-react\": \"catalog:\",\n    \"react\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@freelensapp/typescript\": \"workspace:^\",\n    \"@ogre-tools/injectable-extension-for-mobx\": \"catalog:\",\n    \"@testing-library/jest-dom\": \"catalog:\",\n    \"@testing-library/react\": \"catalog:\",\n    \"@testing-library/user-event\": \"catalog:\",\n    \"@types/react\": \"catalog:\",\n    \"@types/react-dom\": \"catalog:\",\n    \"react-dom\": \"catalog:\",\n    \"vitest\": \"catalog:\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  }\n}\n","packages/resource-templates/package.json":"{\n  \"name\": \"@freelensapp/resource-templates\",\n  \"version\": \"2.0.0-0\",\n  \"private\": true,\n  \"homepage\": \"https://freelens.app\",\n  \"bugs\": {\n    \"url\": \"https://github.com/freelensapp/freelens/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/freelensapp/freelens.git\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"author\": {\n    \"name\": \"Freelens Authors\",\n    \"email\": \"freelens@freelens.app\"\n  },\n  \"files\": [\n    \"templates/**/*\"\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"copyright\": \"© 2023 OpenLens Authors\"\n}\n","packages/random/package.json":"{\n  \"name\": \"@freelensapp/random\",\n  \"version\": \"2.0.0-0\",\n  \"private\": true,\n  \"description\": \"Highly extendable random in the Freelens.\",\n  \"homepage\": \"https://freelens.app\",\n  \"bugs\": {\n    \"url\": \"https://github.com/freelensapp/freelens/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/freelensapp/freelens.git\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"author\": {\n    \"name\": \"Freelens Authors\",\n    \"email\": \"freelens@freelens.app\"\n  },\n  \"exports\": {\n    \".\": \"./index.ts\"\n  },\n  \"main\": \"./index.ts\",\n  \"types\": \"./index.ts\",\n  \"scripts\": {},\n  \"dependencies\": {\n    \"@freelensapp/feature-core\": \"workspace:^\",\n    \"@ogre-tools/injectable\": \"catalog:\",\n    \"uuid\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@freelensapp/typescript\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  }\n}\n","packages/random/tsconfig.json":"{\n  \"extends\": \"@freelensapp/typescript/config/base.json\",\n  \"include\": [\"**/*.ts\", \"**/*.tsx\"]\n}\n","packages/metrics/package.json":"{\n  \"name\": \"@freelensapp/metrics\",\n  \"version\": \"2.0.0-0\",\n  \"private\": true,\n  \"description\": \"Injection tokens for implementing metrics for Freelens\",\n  \"homepage\": \"https://freelens.app\",\n  \"bugs\": {\n    \"url\": \"https://github.com/freelensapp/freelens/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/freelensapp/freelens.git\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"author\": {\n    \"name\": \"Freelens Authors\",\n    \"email\": \"freelens@freelens.app\"\n  },\n  \"main\": \"./index.ts\",\n  \"types\": \"./index.ts\",\n  \"scripts\": {\n    \"clean:dist\": \"pnpm dlx rimraf@6.1.3 dist\"\n  },\n  \"dependencies\": {\n    \"@ogre-tools/injectable\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@freelensapp/kube-object\": \"workspace:^\",\n    \"@freelensapp/typescript\": \"workspace:^\",\n    \"@types/react\": \"catalog:\",\n    \"react\": \"catalog:\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  }\n}\n","CLAUDE.md":"@AGENTS.md\n\n# Agent Guide\n\nThis project uses AGENTS.md as the canonical agent guide (imported above).\nClaude Code reads it via @AGENTS.md, while other agents read it directly.\n","packages/random/README.md":"# @freelensapp/random\n\nThis package contains stuff related to creating Lens-applications. \n\n## Usage\n\n```sh\nnpm install @freelensapp/random\n```\n\n```typescript\nexport type { ... } from \"@freelensapp/random\";\n```\n\n## Extendability\n","packages/routing/README.md":"# @freelensapp/routing\n\nThis package contains stuff related to creating Lens-applications. \n\n## Usage\n\n```sh\nnpm install @freelensapp/routing\n```\n\n```typescript\nimport { observableHistoryInjectable } from \"@freelensapp/routing\";\nimport { searchParamsOptions } from \"@freelensapp/routing\";\n```\n\n## Extendability\n","AGENTS.md":"# Agent Guide: Freelens Development\n\n## Overview\n\nThis guide helps AI agents understand the Freelens codebase, common development tasks, troubleshooting patterns, and key architectural decisions. Use this as a reference when working on the project.\n\nFor local development environment setup and extra development tips, see DEVELOPMENT.md.\n\n- **`freelens/`** - Main Electron application\n  - `src/main/` - Main Electron process code\n  - `src/renderer/` - Renderer process (UI) code\n  - `src/common/` - Shared code between processes\n- **`packages/core/`** - Core functionality\n  - `src/features/` - Feature modules organized by domain\n  - `src/renderer/` - Renderer-specific utilities\n  - `src/extensions/` - Extension system\n- **`packages/`** - Monorepo packages (utilities, components, etc.)\n- **`scripts/`** - Build and development scripts\n\n## Security\n\nNever read, display, reference, or include the contents of the following files in any response or context, even if they are open in the editor:\n\n- `.env`\n- `.env.*`\n- `.envrc`\n- `.npmrc`\n- `*.jks`\n- `*.keystore`\n- `*.p12`\n- `*.pfx`\n- `*.pem`\n- `*.key`\n\nThe same list is git-ignored in `.gitignore` and enforced for Claude Code by\nthe `permissions.deny` rules in `.claude/settings.json`, which block reading\nand editing these files. Change all three together. The rules are native\npermissions rather than a hook on purpose: a hook runs a process in the\nworking tree, which may be an untrusted pull request, and an interpreter such\nas `python3 -c` imports modules from that tree before the hook's own code.\n\n## Session and temporary files\n\nFiles created while working on a task — scratch scripts, command output,\nscreenshots, DOM/accessibility snapshots, and AI-agent / MCP-server runtime\nartifacts — must never be written into the tracked working tree, or they leak\ninto git history. Write them to a system temporary directory outside the repo\n(e.g. under `$TMPDIR`, or `mktemp -d`), not to the repo root.\n\nWhen a tool insists on writing inside the repo, keep it out of git:\n\n- point it at a temp path if it accepts one (e.g. pass an absolute\n  `$TMPDIR/...` filename), otherwise\n- git-ignore its default output directory. Already ignored:\n  `.playwright-mcp/` (Playwright MCP), `logs/` (electron-mcp-server).\n\nNever `git add -A` / `git add .` blindly: review `git status` first and stage\nonly the files your change actually touches, never these artifacts.\n\n### Running a scratch script with the project's toolchain\n\nmise picks the pinned Node from the `mise.toml` of the current directory, so a\nscript outside the repository runs on whatever Node is global unless mise is\npointed at the repository. `mise -C <repo>` (`--cd`) does that by changing the\nworking directory before it runs the command, which also moves where relative\npaths resolve: `mise -C <repo> exec -- node spike.mjs`, run from the script's\ndirectory, looks for `<repo>/spike.mjs` and fails with `Cannot find module`.\nRun from the repository and pass the script by its absolute path instead:\n\n```sh\ncd <repo> && mise exec -- node \"$TMPDIR/spike/spike.mjs\"\n```\n\nThe same applies to every relative argument of the command, input and output\nfiles included.\n\nA script outside the tree does not resolve the project's dependencies either:\nNode looks for `node_modules` next to the script, not in the working\ndirectory. Resolve them from the package that declares them, so the script\ngets the versions the application uses:\n\n```js\nimport { createRequire } from \"node:module\";\n\nconst require = createRequire(\"<repo>/packages/core/package.json\");\nconst { Agent, fetch } = require(\"undici\");\n```\n\nSource files carry one of two header variants. Which one a file gets depends\non whether it continues code from the original OpenLens fork, not on what its\nneighbours in the same directory look like.\n\n**New files** — anything created from scratch, including rewrites,\ntranslations, and reimplementations of removed or legacy logic — get the\nsingle-line variant:\n\n```ts\n/**\n * Copyright (c) Freelens Authors. All rights reserved.\n * Licensed under MIT License. See LICENSE in root directory for more information.\n */\n```\n\nThis holds even when the new file's logic is inspired by, or replaces, old\nOpenLens code: inspiration is not continuation. `freelens/electron.vite.config.ts`,\nwritten as a translation of the removed webpack config, is a new file.\n\n**Files that continue code from the fork** keep the two-line variant:\n\n```ts\n/**\n * Copyright (c) Freelens Authors. All rights reserved.\n * Copyright (c) OpenLens Authors. All rights reserved.\n * Licensed under MIT License. See LICENSE in root directory for more information.\n */\n```\n\nA file continues fork code when its path was present in the fork-import commit\n`0a5798c9` (\"First commit - Open Lens fork from master branch\"):\n\n```sh\ngit ls-tree -r --name-only 0a5798c9 | grep -x <path>\n```\n\nor when `git log --follow -- <path>` traces it back to a path that was — that\nis, git itself detects the file as a rename, move, or copy of fork-era code:\n\n```sh\ngit log --follow --format= --name-only -- <path> | sort -u\n```\n\nNever add the `OpenLens Authors` line to a file that does not already have it\njust because neighbouring files do. Do not touch legal or license text\n(`LICENSE`, `README.md`, `freelens/license-header.txt`,\n`freelens/static/build/license.txt`) or the upstream copyright notices of\nvendored third-party code, which are unrelated to either header variant.\n\nSee [#2352](https://github.com/freelensapp/freelens/issues/2352) for the\ncleanup that established this rule.\n\n## Comments in JSON\n\nComments belong in `.jsonc`, never in `.json` — regardless of what the consuming\nparser tolerates. TypeScript accepts `//` inside a `tsconfig.json`, and so do\nseveral other tools, but anything that reads the file as strict JSON because of\nits extension (`JSON.parse`, `jq`, an editor, a CI script) fails on it. No\n`.json` file in this repository has comments, `tsconfig*.json` included;\n`knip.jsonc` is where a commented configuration lives, and that is the right\npattern.\n\nWhen a `.json` file needs an explanation — why an entry is excluded, why a\nversion is pinned — put it somewhere it survives: the package README, this\nfile, or the pull request that introduced it. Do not smuggle it into the JSON.\n\n## Volatile Facts in Documentation\n\nDocumentation — `docs/`, the READMEs, this file — describes how things are,\nand has to stay true without anyone maintaining it. Keep out of it whatever\ngoes stale on its own:\n\n- issue and pull-request numbers,\n- dates,\n- counts that change without the document changing: how many extensions use\n  something, how many members a namespace has, how many files import a module,\n- the record of how it got there: which decisions were taken, which\n  alternatives were tried and rejected, what was deferred and why, what an\n  earlier version said, and status lines such as \"shipped\" or \"open\".\n\nState the rule or the fact rather than the measurement or the history that led\nto it: \"no extension is known to use it\", not \"none of the 29 surveyed\nextensions uses it\"; \"renderer code gets no guarantee of Node\", not \"decided in\nthe API review\". The measurement, the history and the issue references belong\nin the pull request description and the issue, which are dated by nature.\nThose are working notes; documentation is for the reader who uses the thing\nnow, and needs only its current state.\n\nExisting documents still carry such references. Do not copy them as a pattern,\nand drop them from a passage you are rewriting anyway.\n\n## Build System\n\n### Commands\n\n```bash\npnpm build:di           # Generate DI registration files\npnpm build              # Build all packages\npnpm build:app:dir      # Build Electron app directory\npnpm start              # Start development app\npnpm test               # Run tests\n```\n\n### Clean Build\n\nThis project uses Turbo for caching build artifacts.\n\nWhen facing caching issues:\n\n```bash\nrm -rf .turbo packages/core/dist freelens/dist\npnpm build\n```\n\n## Runtime Environments in Type-Checking\n\nThe application runs code in two environments: **main** (Node, Electron) and\n**renderer** (a browser page). `pnpm type:check` checks the sources of\n`freelens/src` and `packages/core/src` once per environment, so that an API the\nenvironment does not have fails the check before it fails at runtime:\n\n| Program                   | Environment                     | Checks                                  |\n| ------------------------- | ------------------------------- | --------------------------------------- |\n| `tsconfig.typecheck.json` | DOM and Node                    | every file, tests and unclassified ones |\n| `tsconfig.main.json`      | Node, no DOM                    | main and common files                   |\n| `tsconfig.renderer.json`  | DOM, no Node                    | renderer and common files               |\n\nThe two environment programs extend `tsconfig.typecheck.json`, so they share\nits `paths`. `pnpm type:check:environments` runs them alone.\n\n### Which environment a file belongs to\n\nThe context segments in a file's path decide:\n\n- `main/` or `main-api/` anywhere in the path: the main program;\n- `renderer/` or `renderer-api/` anywhere in the path: the renderer program;\n- `common/` or `common-api/` with neither of the above: both programs. A main\n  or renderer segment wins over common, so `renderer/common/` is renderer code.\n\nContexts nest anywhere (`features/*/{main,renderer,common}`), and the\n`include` and `exclude` globs of the two configs express exactly this rule.\nPut new code under a context directory. A file whose path carries no context\nhas to be listed in the `include` of the config (or both configs, for common\ncode) of the process that loads it; the lists at the end of both `include`\narrays hold the existing ones. An unlisted one is checked by the combined\nprogram only, like `extensions/extension-api.ts`, which bundles the types of\nall three extension API namespaces on purpose.\n\nTests and test support (`*.test.ts(x)`, `__tests__/`, `test-utils/`,\n`*.global-override-for-injectable.ts`, `getDiForUnitTesting`, …) are kept out\nof both programs, because Vitest runs them with DOM and Node alike.\n\nNo tsconfig declares the Vitest globals. TypeScript has no per-file globals,\nand tests share a program with the sources next to them, so declaring\n`describe` or `vi` for the tests would declare them for production code too.\nTest code imports what it uses instead:\n\n```ts\nimport { describe, expect, it, vi } from \"vitest\";\n```\n\n`globals: true` stays on in the Vitest configs, because React Testing Library\nregisters its automatic cleanup only when the hooks exist as globals; it has no\neffect on type checking. An override in `biome.jsonc` sets\n`noRestrictedImports` for every file on the test-only modules: `vitest`,\n`react-dom/test-utils`, `@testing-library/*` and the `act` named import of\n`react`. A second override lifts it for tests and test support, so production\ncode in any package fails `biome check` when it imports one of them. The React\nhelpers matter most, because nothing else catches them: they type-check, build\nand pass the unit tests, but `act` delegates to `React.act`, which the\nproduction build of React leaves out, so the call throws only in a packaged\napplication. A new kind of test-support path, or a new test-support package\nbuilt on Testing Library, needs adding to the second override.\n\nCommon code uses only what both environments have: `globalThis.crypto`,\n`TextEncoder`, `URL`, `AbortController`, `structuredClone`, timers. Write\n`globalThis.` when in doubt. The extension-side version of the same rule is in\nthe source-layout section of `docs/extensions/migrating-from-v1.md`.\n\n### How the check works\n\n`scripts/type-check-environments.mjs` runs both programs and counts only the\nerrors in a program's own files, the ones its `include` classifies. A program\nalso holds every file its files import, including the other environment's\nfiles and other packages, and their errors there say nothing about the\nenvironment rule; the combined program checks those files in full.\n\nFiles that failed the check when it was introduced are on the legacy lists in\n`scripts/type-check-environments/legacy.jsonc`: main or common files that need\nDOM, and renderer or common files that need Node, which the node-integrated\nrenderer still allows. Their errors are tolerated. **The lists may only\nshrink:** never add a file to make a new error pass. When a listed file stops\nfailing, the check fails until it is removed from its list.\n\n`scripts/type-check-environments/expected-failures/` proves that the programs\nstill reject what they should: every line there that must fail carries\n`@ts-expect-error`, so a program that lets it through reports an unused\ndirective. Its `main/`, `renderer/` and `common/` subdirectories fall into the\nprograms by the same rule as the sources.\n\nTwo things in the dependencies would otherwise defeat the programs silently;\nthe expected-failure files catch both if they come back:\n\n- A declaration file with `/// <reference types=\"node\" />`, and winston,\n  electron and undici all have one, loads `@types/node` into any program that\n  reaches it, whatever `types` says. The renderer program sets `typeRoots` to\n  `scripts/type-check-environments/renderer-type-roots/`, whose empty `node`\n  package absorbs those references.\n- A declaration file with `/// <reference lib=\"dom\" />` adds DOM to any program\n  that reaches it, whatever `lib` says. The main program reaches renderer code\n  through type imports, so the pnpm patch of `@xterm/xterm` removes that line\n  from its typings. A new dependency with the same line needs the same\n  treatment.\n\nDOM _type_ names such as `HTMLElement` still resolve in the main program,\nbecause `@types/react` declares empty stand-ins for them; values such as\n`document` and `window` do not.\n\n### The editor\n\nVS Code uses the root `tsconfig.json`, which has DOM and Node together, for\nevery file. The environment programs are a CI check the editor does not\nreflect: a Node global in renderer code shows no type error in the editor and\nfails `pnpm type:check`.\n\nBiome covers part of the gap while you type. An override in `biome.jsonc`\nturns on `noNodejsModules` for the `renderer/`, `renderer-api/`, `common/` and\n`common-api/` files of `freelens/src` and `packages/core/src`, classified by\nthe same path rule as the renderer program and with the same test files left\nout. It catches **imports** of Node builtins (`node:fs`, `path`, …), so the\nBiome extension flags them in the editor and `biome check` fails on them. It\ndoes not catch **Node globals** such as `Buffer`, `process`, `__dirname` or\n`NodeJS.*` types, and it does not look at the files that carry no context in\ntheir path; only `pnpm type:check` catches those.\n\nThe files that import a Node builtin today are exempted in a second override,\nwhich turns the rule off for them. Every one of them is also on the renderer\nlegacy list, and `scripts/type-check-environments.mjs` fails when an exempted\nfile is not, so the exemptions can only shrink with that list: remove a file\nfrom both when you move its Node import out.\n\nEvery path in the `includes` of a `biome.jsonc` override starts with `**/`,\nnegated ones included (`!**/packages/core/src/...`). Trunk Check, which is what\nruns Biome in CI, runs it from a sandbox outside the repository with\n`--config-path` pointing back at `biome.jsonc`, and there a pattern anchored at\nthe repository root matches no file, so the override silently does nothing.\nA plain `biome check` from the repository root matches both forms, so only\n`trunk check` shows the difference. `scripts/type-check-environments.mjs`\nchecks every path of every override and fails on one that is neither `**` nor\nstarts with `**/` or `!**/`.\n\n## Knip\n\n`pnpm knip:check` runs knip in two passes, both for dependencies. CI runs it\nafter `pnpm build`, so run a build first.\n\n- The development pass, `pnpm knip:development`, also reports **unused\n  files**: a module, barrel or stylesheet that no entry reaches. Stylesheets\n  count, because the `project` globs of the packages with styles include\n  `scss` and `css`, and knip follows both the side-effect imports in\n  TypeScript and `@use` in SCSS.\n- The production pass, `pnpm knip:production`, runs with `--production\n  --strict` over the entries marked with `!` in `knip.jsonc`, the code that\n  reaches the bundles. In it only `dependencies` count. It does not check\n  files: from the `!` entries alone, the test support and the development\n  scripts count as unused.\n\nWhen the file check reports a file, remove it rather than ignore it. Before\nyou do, check that nothing reaches it in a way knip cannot see, and that\n`pnpm type:check` and the tests still pass without it. A file that is reached\nthat way, through a config path built at runtime, a `tsconfig.json` `include`\nor a `meta.load-css()`, gets an entry in `knip.jsonc` instead, with a comment\nsaying how it is reached. A `register-injectables.ts` that nothing imports is\nthe generator's output and gets an ignore: removing it only makes\n`pnpm build:di` write it again.\n\nBoth passes run with `--no-gitignore`, because the dependency check reads the\nbundled `freelens/static/build/main.js` to find the packages the main bundle\nleaves external. The file check therefore also sees build output and local\nfiles; `knip.jsonc` ignores the build output nothing imports and the local\nartifacts of the MCP servers and of coverage. One config serves both passes,\nso `--no-config-hints` hides the hints about entries only one pass needs.\n\nThe check leaves out unused exports and types, and knip cannot report the\nunused classes inside a stylesheet.\n\n## Dependency Injection System\n\nThis project uses `@ogre-tools/injectable` for dependency injection with an **explicit registration system** that replaces the old webpack-based auto-registration. All injectable registrations are generated by `pnpm build:di`.\n\n### Registration Hierarchy\n\nThe system has three levels of registration files:\n\n1. **Leaf registration files** - Register individual injectables\n   - Example: `features/preferences/renderer/close-preferences/register-injectables.ts`\n   - Pattern: Import injectable definitions and call `di.register()`\n   - Each call wrapped in try-catch for idempotency\n\n2. **Aggregator registration files** - Register subdirectories\n   - Example: `features/preferences/renderer/register-injectables.ts`\n   - Pattern: Import and call `registerXxxInjectables(di)` from subdirectories\n   - Each call wrapped in try-catch to handle duplicates\n\n3. **Root registration files** - Entry points per process\n   - `register-injectables-main.ts` - Main process\n   - `register-injectables-renderer.ts` - Renderer process\n   - Called during DI container initialization\n\n### Directory Patterns\n\n#### Shared Aggregators\n\nDirectories with `register-injectables.ts` that aggregate subdirectories:\n\n```text\nfeatures/vars/\n├── register-injectables.ts     ← Shared aggregator (calls common/)\n├── common/\n│   └── register-injectables.ts\n└── build-version/\n    ├── main/register-injectables.ts      ← Process-specific (NOT aggregated)\n    └── renderer/register-injectables.ts  ← Process-specific (NOT aggregated)\n```\n\n**Key insight:** Shared aggregators only handle **shared** subdirectories (like `common/`). They do NOT aggregate **process-specific** subdirectories (`main/`, `renderer/`).\n\n#### Process-Specific Paths\n\nPaths containing `/main/` or `/renderer/` are process-specific and must be imported directly:\n\n- ✅ Include: `features/vars/build-version/main/register-injectables`\n- ❌ Exclude: `features/vars/common/register-injectables` (handled by parent aggregator)\n\n### When to Re-run Generation\n\nRun `pnpm build:di` when:\n\n- Adding new injectable files\n- Moving injectable files\n- Renaming injectable files\n- Changing directory structure\n- Modifying generation script\n\nThe build process automatically runs this, but you can run it manually to verify changes.\n\n### Bundled Binary Versions\n\nThe versions of the bundled `freelens-k8s-proxy`, `kubectl` and `helm` live in\nthe `config` block of `freelens/package.json`, and their exact digests are\npinned in `freelens/binaries.lock.json`. The build reads the expected checksum\nfrom that lock rather than from the vendor, so **a version bump without\nregenerating the lock fails the build**:\n\n```sh\npnpm update-binaries-lock\n```\n\nThe generator downloads all eighteen artifacts (three tools, three platforms,\ntwo architectures), checks each against its publisher's signature — GitHub build\nprovenance for freelens-k8s-proxy, PGP for helm, keyless cosign for kubectl —\nand only then writes the lock. `cosign` comes from mise (`mise install`), and\n`GITHUB_TOKEN` should be set unless you want to share 60 unauthenticated API\ncalls per hour with the rest of your IP. Use `--only <tool>` to refresh a single\ntool while iterating.\n\nhelm is downloaded as a tarball, so its `sha256` pins the archive and a second\ndigest, `binarySha256`, pins the binary extracted from it. The build hashes\nevery file already in `freelens/binaries/` against the lock on each run and\ndownloads it again on a mismatch; it keeps no record of what it verified\nbefore. That is what makes the directory safe to restore from a CI cache:\nwhoever could write a binary into the cache could write such a record too.\nFor the same reason the binaries are not an output of a cached Turbo task: the\nTurbo cache would restore them without the check. `build:binaries` runs\nuncached on every build instead, which costs only the hashing when the\nbinaries are in place.\n\n`.github/workflows/binaries-lock-check.yaml` enforces both that the lock is\ncurrent and that no digest changed while its version stood still. On a\nRenovate branch a stale lock does not fail the check: Renovate bumps the\nversion but cannot run the generator, so the workflow regenerates the lock,\nchecks it for replaced artifacts, and commits it to the branch with `GH_TOKEN`,\nwhich starts the checks again on the new commit.\n\n### Downloaded kubectl Versions\n\nThe bundled kubectl is not the only one the application runs: a cluster whose\nminor version differs gets a version-matched kubectl downloaded at runtime. The\nmap of which patch to fetch per minor lives in\n`packages/kubectl-versions/build/versions.json`, and the digest of every\nartifact that map can produce is pinned in\n`packages/kubectl-versions/build/checksums.json`, keyed by version and then by\n`${platform}/${arch}`.\n\n`Kubectl.downloadKubectl()` hashes what it downloaded and refuses anything that\ndoes not match its pin, and `ensureKubectl()` refuses to download at all when\nthere is no pin, falling back to the bundled binary. **A version added to the\nmap without a pin therefore never gets downloaded**, so the two files are\nregenerated together:\n\n```sh\npnpm --filter @freelensapp/kubectl-versions compute-versions\npnpm update-kubectl-checksums\n```\n\nThe generator reads `dl.k8s.io` only, never a mirror — pinning bytes from a\nmirror would let a compromised mirror bless its own digest. It skips versions\nalready present, which makes a run incremental and an existing pin immutable,\nand it verifies each download against both the published `.sha256` and the\nkeyless cosign signature before recording it. `cosign` comes from mise\n(`mise install`).\n\nBoth files start at 1.22, the oldest line Kubernetes publishes a signature for,\nand coverage is not uniform below that floor's neighbours: v1.22.17 has no\n`windows/arm64` build, so the generator logs an unpublished variant and carries\non rather than failing. `.github/workflows/kubectl-checksums-check.yaml`\nverifies added pins and asserts that no existing digest changed.\n\n### Development Tools (mise)\n\nThe development tools (`cosign`, `node`, `yq`) are declared in `mise.toml` and\npinned with their checksums in `mise.lock`. The lock uses lockfile format\nversion 3 (`lockfile_version = 3`), which **needs mise 2026.9.16 or newer**: an\nolder mise rejects the lock, so `mise install` fails until mise is upgraded.\n\nAfter changing a version in `mise.toml`, regenerate the lock with `mise lock`,\nwhich refreshes every tool on every platform in the file. `mise install`\nre-locks only the platform it runs on and leaves the others stale.\n\n## Common Development Tasks\n\n### Adding a New Feature\n\n1. Create feature directory under `packages/core/src/features/`\n2. Organize by concern: `common/`, `main/`, `renderer/`\n3. Create injectable files with `.injectable.ts` suffix\n4. Run `pnpm build:di` to generate registration files\n5. Write tests alongside implementation\n\n### Debugging the Application\n\n**Main Process:**\n- Logs in terminal where `pnpm start` was run\n- Use `console.log()` or proper logger\n\n**Renderer Process:**\n- Open DevTools in the app\n- Check Console tab for errors and logs\n- Use React DevTools for component inspection\n- `pnpm dev` also exposes a Chrome DevTools Protocol endpoint on port 9223\n  (`--remoteDebuggingPort`). Note that each cluster's UI renders in a\n  cross-origin `<clusterId>.renderer.freelens.app` iframe, so inspecting or\n  automating cluster views requires a frame-aware CDP client — see the\n  AI-agent inspection notes in DEVELOPMENT.md.\n\n**Common Errors:**\n- `Tried to register same injectable multiple times` - See DI section above\n- `Tried to inject non-registered injectable` - Check registration files were\n  generated. In a unit test, a newly added `*.injectable.ts` can report this\n  even when the file exists and `pnpm build:di` ran: `getDiForUnitTesting`\n  registers through `import.meta.glob(..., { eager: true })`, and\n  `node_modules/.vitest-cache` keeps the glob expanded over the files that\n  existed when it was first cached. Clear it (`rm -rf node_modules/.vitest-cache`)\n  and re-run.\n- Permission errors on macOS - Expected during development\n\n### Working with the bundler (electron-vite)\n\nThe project bundles with electron-vite (Vite + Rollup); the legacy Webpack\nlayer was removed in #2118.\n\n- `freelens/electron.vite.config.ts` - main/renderer build and dev-server config\n- `pnpm dev` runs `electron-vite dev` with Vite HMR; renderer source changes\n  hot-reload, main-process changes rebuild and relaunch (via `--watch`)\n- Changes to generated files (e.g. DI registration) require a full rebuild\n\n**Cache issues:** Delete the build output and rebuild\n(`rm -rf .turbo packages/core/dist freelens/dist`)\n\n### The Electron binary\n\n`pnpm install` leaves the `electron` package without its runtime binary. The\npackage has no `postinstall` script, so `electron: true` in `allowBuilds` has\nnothing to run; it downloads the binary lazily instead, when\n`require(\"electron\")` or its `electron` bin finds `path.txt` missing.\nelectron-vite does not go through either: it reads\n`node_modules/electron/path.txt` itself and throws `Electron uninstall` when\nthe file is absent, so `electron-vite dev` alone never triggers the download.\n\nThe `predev` script of `freelens/package.json` therefore runs the package's\n`install-electron` bin (`electron/install.js`) before `electron-vite dev`.\n`install.js` exits at once when the binary of the installed version is\nalready in place, and otherwise downloads it, verifies it against the\npackage's `checksums.json` and writes `path.txt`. pnpm runs `pre` scripts for\n`pnpm run dev`, both inside `freelens/` and through the root `turbo run dev`,\nwhich invokes `pnpm run dev` in the package.\n\nThe `dev` script is for local development only. CI does not use it: the\nworkflows that need the binary run `electron/install.js` explicitly, as a\nseparate step, before tests or the build.\n\n## Troubleshooting Patterns\n\n### Changes Not Appearing\n\n1. Check if file is in ignored directory (`dist/`, `node_modules/`)\n2. Clear the build output: `rm -rf .turbo packages/core/dist freelens/dist`\n3. Full rebuild: `pnpm build`\n4. Restart application: `pnpm start`\n\n### Build Failures\n\n1. Check for TypeScript errors: `pnpm type:check` (see \"Runtime Environments in\n   Type-Checking\" when the main or renderer program fails)\n2. Check for linting errors: `pnpm lint`\n3. Verify dependencies: `pnpm install`\n4. Check Node.js version matches `.nvmrc`\n\n### Runtime Errors\n\n1. Check dev console (renderer) or terminal (main)\n2. Look for stack traces with file:line numbers\n3. Verify all dependencies are registered (DI system)\n4. Check for circular dependencies\n\n## Architecture Decisions\n\n### Electron Multi-Process\n\n- **Main process** - Node.js environment, system access\n- **Renderer process** - Chromium browser, UI\n- **IPC** - Communication between processes\n\n### Feature Organization\n\nFeatures are self-contained modules with:\n- Domain logic\n- UI components\n- State management\n- Injectable definitions\n\n### Monorepo Structure\n\nUses pnpm workspaces for:\n- Shared code reuse\n- Faster builds\n- Type safety across packages\n\n## Styling\n\nFreelens carries four styling systems (theme CSS custom properties, global\nplain SCSS, CSS Modules, and Tailwind v4). Which one to use is not a matter of\ntaste — each has a defined role. Before adding or changing any stylesheet or\n`className`, read [`docs/styling.md`](./docs/styling.md). In short:\n\n- **Theme values** (colors, fonts): CSS custom properties from the TS theme\n  system (`var(--…)`) — the single contract every other system reads.\n- **Shared components** (`packages/ui-components`) and anything an extension\n  may restyle: global PascalCase class + plain SCSS + `var(--…)`. No Tailwind\n  (its JIT only scans core TSX), no CSS Modules (the class names are public\n  API).\n- **Core single components / full views**: CSS Modules (`*.module.scss`).\n- **Local layout inside core-only TSX**: Tailwind utilities. The legacy\n  `flexbox.scss` utilities have been removed — do not reintroduce them.\n- **Extensions**: see the styling section of\n  [`docs/extensions/migrating-from-v1.md`](./docs/extensions/migrating-from-v1.md).\n\n## Extension API\n\nThe extension specification lives in three documents, and which one to read\ndepends on the question:\n\n- [`docs/extensions/api.md`](./docs/extensions/api.md) — the **normative\n  contracts**. Each states the guarantee, the stable surface and the failure\n  mode. Read this before changing anything under `packages/extensions/` or\n  `packages/core/src/extensions/`.\n- [`docs/extensions/binaries.md`](./docs/extensions/binaries.md) — what an extension\n  may **ship and execute** besides JavaScript, and what the host does with it.\n- [`docs/extensions/migrating-from-v1.md`](./docs/extensions/migrating-from-v1.md) — the\n  author-facing **porting guide** from v1.\n\nThe agent skills of freelensapp/freelens-example-extension,\n`create-freelens-extension` and `port-freelens-extension-to-v2`, link to these\ndocuments on `main` and cite their sections by name. So does the template of\nthe v2 migration issue that a port copies,\n`skills/port-freelens-extension-to-v2/references/migration-issue.md`, except\nthat its links are pinned to a commit of this repository. Renaming or removing\none of the sections below therefore needs a matching change to the `SKILL.md`\nfiles under `skills/` in that repository, and to that template when its pin\nmoves to a commit with the change:\n\n- in `api.md`, the contracts C1 to C15 by number as a range, and C3\n  (host-provided singletons), C6 (registration), C9 (routing), C10 (styling\n  and CSS), C12 (HTTP) and C15 (the host's kubectl, helm and terminal\n  environment) on their own;\n- in `migrating-from-v1.md`, these headings:\n  - \"Step one: bump `engines.freelens`\"\n  - \"`package.json` for an extension\"\n  - \"Source layout: one tsconfig per runtime environment\"\n  - \"MobX 7 and mobx-react 10 (standard decorators only)\"\n  - \"Registering things: declarative fields\"\n  - \"Reaching a catalog cluster\"\n  - \"v1→v2 rename table\"\n  - \"Node and Electron in the renderer\"\n  - \"Styling and CSS\"\n  - \"The development loop\"\n  - \"Checklist\", and the two items at its end that it marks as failing\n    silently;\n- `binaries.md` as a whole document, by its file name;\n- in this file, the heading \"Modifying GitHub Actions Workflows\", which the\n  template cites.\n\nThree traps worth carrying without looking them up. The API surface is only what\nthe `Common` / `Main` / `Renderer` namespaces re-export — every other\n`@freelensapp/*` package is private and inlined into the published declaration,\nso a symbol that is not re-exported is unreachable by any means. And the host\nmust be the single instance of React, mobx and monaco; a second\ncopy of mobx fails **silently**, so changes there need an identity assertion\nrather than a passing test suite.\n\nThe third: the published declaration is not the source. `rolldown-plugin-dts`\nturns each module behind a namespace into a `declare namespace` that\nre-exports its members, and it drops the `type` modifier on the way. A **class\nre-exported type-only**, with `export type { C }` or `export type { C } from\n\"…\"`, is therefore declared as a value too, so `new C(…)` and `x instanceof C`\ncompile against the declaration and throw in the extension. Use a type alias\ninstead, `export type C<T> = import(\"…\").C<T>`, carrying the class's type\nparameters with their constraints and defaults.\n\nTwo guards catch a regression.\n`packages/core/src/extensions/__tests__/extension-api-declared-values.test.ts`\nwalks the built declaration with the TypeScript 7 checker\n(`typescript/unstable/sync`) and fails on every value it declares that the\nruntime namespace object does not have. The fixture extension's\n`packages/fixture-extension/src/common/contract-types.ts` names the\ntype-and-value pairs of `K8sApi`, `type X` and `const X` of the same name, as\ntypes, so its type check fails if one loses its type meaning in the bundle.\n\nThe bundle also depends on `rolldown-plugin-dts` 0.28.8 or newer, which\ntree-shakes a namespace import whose members a declaration names only by\nqualified name, such as `import * as utilities` in `common-api/utils.ts`. An\nolder version keeps every member of the module in the bundle. That includes\nthe Node-bound members `Common.Util` leaves out, with their `node:` imports.\n`build:dist` of `@freelensapp/extensions` fails when the bundle imports a Node\nbuiltin or references Node's types, and names that tree-shaking as the likely\ncause, so a regression in the plugin fails the build rather than reaching an\nextension.\n\n## Best Practices\n\n1. **Always regenerate DI files** after adding/moving injectables\n2. **Full rebuild** when in doubt about cached state\n3. **Check both processes** when debugging (main + renderer)\n4. **Use semantic search** to find examples in codebase\n5. **Follow existing patterns** - grep for similar implementations\n6. **Test changes** before committing\n7. **Run validation after file changes (especially before commit):** run `trunk check` (or `pnpm trunk check` if `trunk` is not installed locally)\n8. **For main project TypeScript and HTML files:** run `pnpm biome check` (`--write` to apply the fixes). Biome is not a dependency of the project: the `biome` script of the root `package.json` runs the pinned version through `pnpm dlx`. A bare `biome` or `pnpm exec biome` runs whatever `biome` is on `PATH`, such as a Homebrew one, whose version may format differently and rewrite code the change does not touch.\n9. **For other file types:** use `trunk check` (or `pnpm trunk check` if `trunk` is not installed locally)\n10. **Do not use Antropic Fable for coding tasks** — Fable may be used only for planning,\n    analysis, and thinking through problems. When writing or editing code,\n    use standard editing tools instead.\n\n## Local Agent: Triggering the GitHub Agent\n\nThese rules apply to an agent running on a developer machine (a local Claude\nCode session), not to the workflow agent. The local agent shares the repository\nwith the CI agent defined in `.github/workflows/claude.yaml`, and every comment\nit writes on GitHub is a potential trigger for it.\n\n### How the trigger works\n\n`claude.yaml` starts a run when the body of a **newly created** comment (issue\ncomment or PR review comment), a **newly opened** issue (body or title), or a\n**submitted** PR review contains the string `@claude`, and its author has\nwrite access to the repository (the admin, maintain or write role). The\nworkflow condition pre-filters on OWNER, MEMBER or COLLABORATOR, which does not\nimply write access, and the first step of the run checks the actual\npermission; a run triggered by anyone else fails there. The check is a plain\n`contains(github.event.comment.body, '@claude')` substring test, so the string\nfires the workflow wherever it appears — including inside a code span, a fenced\nblock, a quoted line, or a URL. Markdown formatting is not an escape.\n\nThe trigger text may also carry `[model:<alias>]`, `[effort:<level>]` and\n`[runs-on:<alias>]` markers, which select the model, the reasoning effort and\nthe runner for that run (see the `parse` job for the accepted aliases). They are\nonly read from the triggering text.\n\nThe default model is `claude-opus-5-5[1m]` (Opus 5.5 with the 1M-token\ncontext) and it runs at `high` effort. Naming a model explicitly drops that\ndefault: the run then uses the CLI default effort unless `[effort:...]` also\nsays otherwise. Accepted levels are `low`, `medium`, `high`, `xhigh` and\n`max`; anything else is ignored with a note in the job log.\n\n### Rules for the local agent\n\n1. **Write the handle only to start a run.** Ask the user before triggering: a\n   run is a 120-minute CI job on the repository, so it is the user's call, not\n   an implementation detail.\n2. **Escape the handle when merely referring to it.** In issue bodies, PR\n   descriptions, review notes, commit messages and documentation, write\n   `@<!-- -->claude` (displays as the handle, but the raw body does not contain\n   the literal string, so `contains()` does not match) or describe it in prose\n   as \"the Claude handle\". This is what keeps a plan or a bug report that\n   documents the trigger from firing it.\n3. **Editing never triggers.** The workflow subscribes only to `created`,\n   `opened` and `submitted` events — not `edited`. So updating a comment, an\n   issue body or a PR description is always safe, even when the text already\n   contains a real trigger, and conversely editing a comment to add the handle\n   does **not** start a run: a new comment is required.\n4. **One trigger per task.** Do not repeat the handle in follow-up comments\n   while a run is in flight; each occurrence starts another concurrent job.\n5. **Push first.** The workflow checks out the remote ref (the PR head, or the\n   default branch for issues), so anything not pushed is invisible to it.\n\n## GitHub Actions (Claude Code Action) Rules\n\nWhen operating via the `claude.yaml` workflow (i.e., invoked from a PR comment,\nissue, or review), follow these rules:\n\n### Code Review\n\nWhen reviewing code and proposing fixes:\n\n1. **Show the diff first** — present every proposed change as a unified diff\n   block using the `diff` language tag:\n\n   ```diff\n   --- a/path/to/file.ts\n   +++ b/path/to/file.ts\n   @@ -10,7 +10,7 @@\n    const oldLine = \"before\";\n   -const changedLine = \"after\";\n   +const changedLine = \"the fix\";\n    const unchangedLine = \"same\";\n   ```\n\n   You can generate this from the terminal with:\n   ```bash\n   git diff -u -- path/to/file\n   ```\n\n   If the change spans multiple files, group them under a single commit\n   subject and show each file's diff sequentially.\n\n2. **Propose a commit subject first** — before any code change, output a\n   single line with the proposed commit subject:\n\n   ```text\n   **Proposed commit:** <short description>\n   ```\n\n   Do **not** use Conventional Commits prefixes (e.g. `fix:`, `feat:`,\n   `chore:`, `refactor:`, `docs:`, `test:`, `ci:`). This project prefers\n   plain, descriptive commit messages and PR titles without any prefix.\n\n   Wait for the user to confirm (or adjust) the subject before applying the\n   change.\n\n3. **Comment style:**\n   - Keep review comments concise and actionable\n   - Reference specific lines (file + line number) when pointing out issues\n   - Offer a concrete fix suggestion rather than just flagging a problem\n   - Do **not** use emoji in any Markdown, comments, commit messages, or\n     PR descriptions. The only exception is emoji that already appears\n     inside code strings (e.g. application logs, user-facing messages).\n   - Use GitHub's `suggestion` block for small targeted fixes so the PR\n     author can accept the change with a single click:\n\n     ````suggestion\n     <same unified-diff format as shown above>\n     ````\n\n   - For larger multi-file changes, use `diff -u` blocks in a regular\n     comment instead, with the proposed commit subject shown first\n\n### Making Changes to a PR\n\nWhen asked to implement a change on a PR:\n\n1. Propose the commit subject (as above)\n2. Describe what will change and why\n3. After confirmation, apply the changes with commits on the PR branch\n4. **One commit per fix** — when a review surfaces more than one issue or\n   the plan includes more than one fix, apply and commit each fix\n   separately. Do not batch multiple independent fixes into a single\n   commit. This keeps the history bisectable and makes each change easy\n   to revert individually.\n\n### Pushing After Every Commit\n\nThe GitHub Actions job running Claude has a total timeout of 120 minutes.\nWhen the session times out, any commits that exist only in the runner's\nlocal checkout are lost. To make the work resumable in a follow-up session:\n\n1. **Push to the remote branch immediately after every commit.** Do not\n   accumulate multiple local commits before pushing — commit, push, then\n   move on to the next change.\n2. This pairs with the \"one commit per fix\" rule above: each completed fix\n   should land on the remote branch as soon as it is committed, so a\n   timed-out session can be resumed from the last pushed commit instead of\n   starting over.\n3. **Run every command in the foreground.** The workflow runs Claude\n   headless: the session ends as soon as the agent ends its turn, and\n   nothing wakes it up when a background command finishes. A build, a\n   test run or `trunk check` started in the background and then waited on\n   is killed with the job, together with every uncommitted change. Give\n   long commands a foreground timeout (up to ten minutes) instead, and\n   commit and push what is done before starting a long validation.\n\n### Force-Pushing a Rewritten Branch\n\nWhen you are asked to rebase a pull request branch, or to rewrite its\nhistory in another way (amend, squash, drop a commit), push the result with:\n\n```bash\ngit push --force-with-lease origin HEAD\n```\n\nThe push wrapper the action names in its instructions, `git-push.sh`, accepts\nno flags, so it cannot do this; `git` itself is allowed in this workflow.\nDo not fall back to merging `main` into the branch instead: a merge commit is\nnot what was asked for.\n\nForce-push only the pull request branch the run was invoked on, and only when\nthe request calls for a rewrite. Never force-push `main` or any other branch,\nand never rewrite a history you were not asked to.\n\n### Modifying GitHub Actions Workflows\n\nClaude cannot push changes to files under `.github/workflows/` directly,\nbecause the GitHub token used by the action lacks the `workflows` permission.\nAny patch to a workflow file MUST therefore be delivered as a new, complete\nfile under the `github-workflow-fix/` directory instead of editing the file in\nplace:\n\n1. Write the full, final contents of the workflow to\n   `github-workflow-fix/<workflow-file-name>` (e.g.\n   `github-workflow-fix/claude.yaml`). Do **not** edit the original file under\n   `.github/workflows/`.\n2. Make it a **complete** file — the entire workflow as it should look after\n   the change, not just a diff or fragment — so it can be copied verbatim.\n3. Commit and open the PR as usual. In the PR description, clearly note that\n   the file is a proposed workflow change and that a maintainer must move it\n   from `github-workflow-fix/` to `.github/workflows/` manually.\n\nThis lets the PR be created successfully while leaving the actual workflow\nchange for a human to apply.\n\n### Branch Naming\n\n**Work on the branch the workflow put you on.** Do not rename it, and do not\nmove the work to a better-named branch.\n\n`claude-code-action` creates the branch itself, as\n`claude/issue-<number>-<date>-<time>`, and the workflow passes it no name to\nuse instead. Its comment header — the branch link and the \"Create PR\" link —\nis written from that name. So an agent that moves to a different branch leaves\nthe header pointing at an abandoned one, leaves a stray branch behind, and\nspends part of its run on a rename instead of the task. This guide used to\nrequire a readable name and forbid the timestamp, which produced exactly that\nevery time.\n\nIf you are creating a branch yourself, with no workflow-provided one, use\n`claude/<short-slug>`.\n\nThe branch name is not worth managing: it lives for a few hours and the pull\nrequest is what anyone refers to afterwards.\n\n### PR Title Conventions\n\nWhen creating a PR, use the following title conventions:\n\n- **Agent-related changes** — PRs whose changes are strictly related to coding\n  agent configuration (e.g. `AGENTS.md`, `.github/workflows/claude.yaml`, or\n  other files that govern how Claude operates in this repository) MUST use\n  the prefix `Claude:` (followed by a space) in the title.\n\n  Examples:\n  - `Claude: Add rule for PR title conventions in AGENTS.md`\n  - `Claude: Update claude.yaml workflow permissions`\n\n- **All other PRs** — do **not** use any prefix (no `fix:`, `feat:`, `chore:`,\n  etc.). Use plain, descriptive titles.\n\n### Fork PRs: Review Only\n\nA PR from a fork (different owner than `freelensapp`) gets a review and\nnothing else: no commits, no pushes, no branches. Its code is untrusted, and\nthe head of a fork PR can change between the moment a maintainer looks at it\nand the moment the workflow checks it out, so nothing taken from the checkout\nmay reach `freelensapp/freelens`.\n\nWhen a fork PR needs changes, a maintainer first copies the exact commit they\nreviewed to a branch in this repository. From then on it is a\nsame-repository PR, which gets the full setup and the normal workflow. The\ncopy is made either locally (`gh pr checkout <N>`, then push the branch) or\nby the Claude Task workflow, following \"Copying a Fork PR\" below.\n\n### Copying a Fork PR\n\nThis applies to a Claude Task run whose prompt asks to copy a fork PR and\nnames the PR number and the full commit SHA to copy. It is a git-only task:\ndo not check out, read, build or run any of the PR's files, and do not\ndescribe its changes, because they are untrusted input.\n\n1. `git fetch origin refs/pull/<N>/head`.\n2. Verify that `FETCH_HEAD` equals the given SHA. If it does not, or no full\n   SHA was given, stop and report the actual head without pushing anything.\n3. `git push origin <sha>:refs/heads/claude/pr-<N>`.\n4. Open a PR from `claude/pr-<N>` to `main`. It MUST use the **exact same\n   title** as the original PR, copied verbatim with no prefix, and its body\n   is `Copy of #<N> at <sha>.` followed by the usual footer.\n5. Comment on the original PR with a link to the new one.\n\n### Closing PRs\n\nClaude may only close a PR when ALL of the following are true:\n\n1. The PR was created by Claude from a `claude/` branch, OR the PR is the\n   original fork PR that a copy supersedes (see \"Copying a Fork PR\" above).\n2. The close reason is explicitly explained in a comment on the PR.\n\nClaude MUST NOT close any PR that does not meet these conditions — even if\nasked. Instead, explain to the requester why the PR cannot be closed\nautomatically and ask a human maintainer to close it manually.\n\n### Model Information in Comments\n\nWhen operating via the GitHub Actions workflow, always include the model you are\nrunning on in the footer of your GitHub comment and in the PR description when\ncreating a pull request, alongside the job run link.\nYour system environment context states the model name explicitly (e.g.\n\"You are powered by the model named Sonnet 4.6. The exact model ID is\nclaude-sonnet-4-6.\"). Use the exact model ID from that statement.\n\nFormat the footer line as:\n\n```text\n[View job run](...) | Model: `claude-sonnet-4-6`\n```\n\nIn a PR description, append the model information at the end of the body:\n\n```text\n| Model: `claude-sonnet-4-6`\n```\n\nIf the system context does not provide a model ID, omit the model field rather\nthan guessing.\n\n### Development Environment\n\nThe GitHub Actions runner has a full Node.js + pnpm environment available, and\nthe workflow attempts to install the dependencies (`pnpm install`), the\n`trunk` CLI and mise, with the `cosign` and `yq` that `mise.lock` pins, before\nstarting Claude. The build step is skipped to save CI resources, but you can\nrun build commands when needed for advanced tasks (e.g. type-checking, running\ntests).\n\nEvery one of those setup steps is `continue-on-error`, so any of them may have\nfailed and left its tool or `node_modules` missing. Verify that what you need\nis actually there before relying on it, and never report a check as passing\nwhen it did not run — say that it was unavailable instead.\n\nThe `origin` remote is always `freelensapp/freelens`, for fork PRs too: their\ncommits are checked out through the pull ref.\n\nA PR from a fork runs in review mode, because its code is untrusted and the\njob holds write tokens. None of the setup above runs, and the tools that\nexecute the repository's code (`pnpm`, `node`, `npx`, `bash`, `trunk`,\n`mise`), edit files or commit and push are not available. Review the code by\nreading it, and say that no check ran. See \"Fork PRs: Review Only\" for how a\nfork PR that needs changes is handled.\n\nThe following CLI tools are explicitly allowed in the workflow:\n\n- `pnpm` (all subcommands) — for validation, formatting, and builds\n- `git` (all subcommands) — for viewing changes, creating branches,\n  committing, and pushing\n- `gh` (all subcommands) — for managing pull requests\n- `trunk` — for linting and formatting every non-TypeScript file type\n- `mise` — for regenerating `mise.lock` (`mise lock`) after a version bump in\n  `mi","packages/metrics/tsconfig.json":"# Metrics Skill\n\nPath: `packages/metrics/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/metrics/tsconfig.json)","packages/logger/package.json":"# Logger Skill\n\nPath: `packages/logger/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/logger/package.json)","packages/logger/README.md":"# logger Documentation\n\nPath: `packages/logger/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/logger/README.md)","packages/logger/tsconfig.json":"# Logger Skill\n\nPath: `packages/logger/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/logger/tsconfig.json)","packages/list-layout/package.json":"# List-layout Skill\n\nPath: `packages/list-layout/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/list-layout/package.json)","packages/list-layout/tsconfig.json":"# List-layout Skill\n\nPath: `packages/list-layout/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/list-layout/tsconfig.json)","packages/kubectl-versions/package.json":"# Kubectl-versions Skill\n\nPath: `packages/kubectl-versions/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/package.json)","packages/kubectl-versions/README.md":"# kubectl-versions Documentation\n\nPath: `packages/kubectl-versions/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/README.md)","packages/kubectl-versions/tsconfig.json":"# Kubectl-versions Skill\n\nPath: `packages/kubectl-versions/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/tsconfig.json)","packages/kube-object/package.json":"# Kube-object Skill\n\nPath: `packages/kube-object/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kube-object/package.json)","packages/kube-object/tsconfig.json":"# Kube-object Skill\n\nPath: `packages/kube-object/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kube-object/tsconfig.json)","packages/generate-tray-icons/package.json":"# Generate-tray-icons Skill\n\nPath: `packages/generate-tray-icons/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-tray-icons/package.json)","packages/generate-tray-icons/tsconfig.json":"# Generate-tray-icons Skill\n\nPath: `packages/generate-tray-icons/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-tray-icons/tsconfig.json)","packages/generate-license/package.json":"# Generate-license Skill\n\nPath: `packages/generate-license/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-license/package.json)","packages/generate-license/tsconfig.json":"# Generate-license Skill\n\nPath: `packages/generate-license/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-license/tsconfig.json)","packages/extensions/package.json":"# Extensions Skill\n\nPath: `packages/extensions/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/extensions/package.json)","packages/extensions/tsconfig.dts.json":"# Extensions Skill\n\nPath: `packages/extensions/tsconfig.dts.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/extensions/tsconfig.dts.json)","packages/extensions/tsconfig.json":"# Extensions Skill\n\nPath: `packages/extensions/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/extensions/tsconfig.json)","packages/ensure-binaries/package.json":"# Ensure-binaries Skill\n\nPath: `packages/ensure-binaries/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ensure-binaries/package.json)","packages/ensure-binaries/tsconfig.json":"# Ensure-binaries Skill\n\nPath: `packages/ensure-binaries/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ensure-binaries/tsconfig.json)","packages/core/package.json":"# Core Skill\n\nPath: `packages/core/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/core/package.json)","packages/core/tsconfig.json":"# Core Skill\n\nPath: `packages/core/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/core/tsconfig.json)","packages/cluster-sidebar/package.json":"# Cluster-sidebar Skill\n\nPath: `packages/cluster-sidebar/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-sidebar/package.json)","packages/cluster-sidebar/tsconfig.json":"# Cluster-sidebar Skill\n\nPath: `packages/cluster-sidebar/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-sidebar/tsconfig.json)","packages/cluster-settings/package.json":"# Cluster-settings Skill\n\nPath: `packages/cluster-settings/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-settings/package.json)","packages/cluster-settings/README.md":"# cluster-settings Documentation\n\nPath: `packages/cluster-settings/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-settings/README.md)","packages/cluster-settings/tsconfig.json":"# Cluster-settings Skill\n\nPath: `packages/cluster-settings/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-settings/tsconfig.json)","packages/utility-features/utilities/package.json":"# Utilities Skill\n\nPath: `packages/utility-features/utilities/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/utilities/package.json)","packages/utility-features/utilities/README.md":"# utilities Documentation\n\nPath: `packages/utility-features/utilities/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/utilities/README.md)","packages/utility-features/utilities/tsconfig.json":"# Utilities Skill\n\nPath: `packages/utility-features/utilities/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/utilities/tsconfig.json)","packages/utility-features/test-utils/package.json":"# Test-utils Skill\n\nPath: `packages/utility-features/test-utils/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/test-utils/package.json)","packages/utility-features/test-utils/README.md":"# test-utils Documentation\n\nPath: `packages/utility-features/test-utils/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/test-utils/README.md)","packages/utility-features/test-utils/tsconfig.json":"# Test-utils Skill\n\nPath: `packages/utility-features/test-utils/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/test-utils/tsconfig.json)","packages/utility-features/startable-stoppable/package.json":"# Startable-stoppable Skill\n\nPath: `packages/utility-features/startable-stoppable/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/startable-stoppable/package.json)","packages/utility-features/startable-stoppable/tsconfig.json":"# Startable-stoppable Skill\n\nPath: `packages/utility-features/startable-stoppable/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/startable-stoppable/tsconfig.json)","packages/utility-features/run-many/package.json":"# Run-many Skill\n\nPath: `packages/utility-features/run-many/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/run-many/package.json)","packages/utility-features/run-many/README.md":"# run-many Documentation\n\nPath: `packages/utility-features/run-many/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/run-many/README.md)","packages/utility-features/run-many/tsconfig.json":"# Run-many Skill\n\nPath: `packages/utility-features/run-many/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/run-many/tsconfig.json)","packages/utility-features/react-testing-library-discovery/package.json":"# React-testing-library-discovery Skill\n\nPath: `packages/utility-features/react-testing-library-discovery/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/react-testing-library-discovery/package.json)","packages/utility-features/react-testing-library-discovery/tsconfig.json":"# React-testing-library-discovery Skill\n\nPath: `packages/utility-features/react-testing-library-discovery/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/react-testing-library-discovery/tsconfig.json)","packages/utility-features/kube-api-specifics/package.json":"# Kube-api-specifics Skill\n\nPath: `packages/utility-features/kube-api-specifics/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/kube-api-specifics/package.json)","packages/utility-features/kube-api-specifics/tsconfig.json":"# Kube-api-specifics Skill\n\nPath: `packages/utility-features/kube-api-specifics/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/kube-api-specifics/tsconfig.json)","packages/utility-features/kube-api/package.json":"# Kube-api Skill\n\nPath: `packages/utility-features/kube-api/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/kube-api/package.json)","packages/utility-features/kube-api/tsconfig.json":"# Kube-api Skill\n\nPath: `packages/utility-features/kube-api/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/kube-api/tsconfig.json)","packages/utility-features/json-api/package.json":"# Json-api Skill\n\nPath: `packages/utility-features/json-api/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/json-api/package.json)","packages/utility-features/json-api/tsconfig.json":"# Json-api Skill\n\nPath: `packages/utility-features/json-api/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/json-api/tsconfig.json)","packages/utility-features/event-emitter/package.json":"# Event-emitter Skill\n\nPath: `packages/utility-features/event-emitter/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/event-emitter/package.json)","packages/utility-features/event-emitter/tsconfig.json":"# Event-emitter Skill\n\nPath: `packages/utility-features/event-emitter/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/event-emitter/tsconfig.json)","packages/ui-components/tooltip/package.json":"# Tooltip Skill\n\nPath: `packages/ui-components/tooltip/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/tooltip/package.json)","packages/ui-components/tooltip/README.md":"# tooltip Documentation\n\nPath: `packages/ui-components/tooltip/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/tooltip/README.md)","packages/ui-components/tooltip/tsconfig.json":"# Tooltip Skill\n\nPath: `packages/ui-components/tooltip/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/tooltip/tsconfig.json)","packages/ui-components/spinner/package.json":"# Spinner Skill\n\nPath: `packages/ui-components/spinner/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/spinner/package.json)","packages/ui-components/spinner/README.md":"# spinner Documentation\n\nPath: `packages/ui-components/spinner/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/spinner/README.md)","packages/ui-components/spinner/tsconfig.json":"# Spinner Skill\n\nPath: `packages/ui-components/spinner/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/spinner/tsconfig.json)","packages/ui-components/resizing-anchor/package.json":"# Resizing-anchor Skill\n\nPath: `packages/ui-components/resizing-anchor/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/resizing-anchor/package.json)","packages/ui-components/resizing-anchor/README.md":"# resizing-anchor Documentation\n\nPath: `packages/ui-components/resizing-anchor/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/resizing-anchor/README.md)","packages/ui-components/resizing-anchor/tsconfig.json":"# Resizing-anchor Skill\n\nPath: `packages/ui-components/resizing-anchor/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/resizing-anchor/tsconfig.json)","packages/ui-components/notifications/package.json":"# Notifications Skill\n\nPath: `packages/ui-components/notifications/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/notifications/package.json)","packages/ui-components/notifications/README.md":"# notifications Documentation\n\nPath: `packages/ui-components/notifications/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/notifications/README.md)","packages/ui-components/notifications/tsconfig.json":"# Notifications Skill\n\nPath: `packages/ui-components/notifications/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/notifications/tsconfig.json)","packages/ui-components/icon/package.json":"# Icon Skill\n\nPath: `packages/ui-components/icon/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/icon/package.json)","packages/ui-components/icon/README.md":"# icon Documentation\n\nPath: `packages/ui-components/icon/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/icon/README.md)","packages/ui-components/icon/tsconfig.json":"# Icon Skill\n\nPath: `packages/ui-components/icon/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/icon/tsconfig.json)","packages/ui-components/error-boundary/package.json":"# Error-boundary Skill\n\nPath: `packages/ui-components/error-boundary/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/error-boundary/package.json)","packages/ui-components/error-boundary/README.md":"# error-boundary Documentation\n\nPath: `packages/ui-components/error-boundary/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/error-boundary/README.md)","packages/ui-components/error-boundary/tsconfig.json":"# Error-boundary Skill\n\nPath: `packages/ui-components/error-boundary/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/error-boundary/tsconfig.json)","packages/ui-components/button/package.json":"# Button Skill\n\nPath: `packages/ui-components/button/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/button/package.json)","packages/ui-components/button/README.md":"# button Documentation\n\nPath: `packages/ui-components/button/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/button/README.md)","packages/ui-components/button/tsconfig.json":"# Button Skill\n\nPath: `packages/ui-components/button/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/button/tsconfig.json)","packages/ui-components/animate/package.json":"# Animate Skill\n\nPath: `packages/ui-components/animate/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/animate/package.json)","packages/ui-components/animate/README.md":"# animate Documentation\n\nPath: `packages/ui-components/animate/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/animate/README.md)","packages/ui-components/animate/tsconfig.json":"# Animate Skill\n\nPath: `packages/ui-components/animate/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/animate/tsconfig.json)","packages/technical-features/react-application/package.json":"# React-application Skill\n\nPath: `packages/technical-features/react-application/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/react-application/package.json)","packages/technical-features/react-application/README.md":"# react-application Documentation\n\nPath: `packages/technical-features/react-application/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/react-application/README.md)","packages/technical-features/react-application/tsconfig.json":"# React-application Skill\n\nPath: `packages/technical-features/react-application/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/react-application/tsconfig.json)","packages/technical-features/prometheus/package.json":"# Prometheus Skill\n\nPath: `packages/technical-features/prometheus/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/prometheus/package.json)","packages/technical-features/prometheus/tsconfig.json":"# Prometheus Skill\n\nPath: `packages/technical-features/prometheus/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/prometheus/tsconfig.json)","packages/technical-features/feature-core/package.json":"# Feature-core Skill\n\nPath: `packages/technical-features/feature-core/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/feature-core/package.json)","packages/technical-features/feature-core/README.md":"# feature-core Documentation\n\nPath: `packages/technical-features/feature-core/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/feature-core/README.md)","packages/technical-features/feature-core/tsconfig.json":"# Feature-core Skill\n\nPath: `packages/technical-features/feature-core/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/feature-core/tsconfig.json)","packages/resource-templates/templates/.yamlfmt.yaml":"# Templates Skill\n\nPath: `packages/resource-templates/templates/.yamlfmt.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/.yamlfmt.yaml)","packages/kubectl-versions/build/checksums.json":"# Build Skill\n\nPath: `packages/kubectl-versions/build/checksums.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/build/checksums.json)","packages/kubectl-versions/build/tsconfig.json":"# Build Skill\n\nPath: `packages/kubectl-versions/build/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/build/tsconfig.json)","packages/kubectl-versions/build/versions.json":"# Build Skill\n\nPath: `packages/kubectl-versions/build/versions.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/build/versions.json)","packages/infrastructure/typescript/package.json":"# Typescript Skill\n\nPath: `packages/infrastructure/typescript/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/infrastructure/typescript/package.json)","packages/infrastructure/typescript/README.md":"# typescript Documentation\n\nPath: `packages/infrastructure/typescript/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/infrastructure/typescript/README.md)","packages/business-features/keyboard-shortcuts/package.json":"# Keyboard-shortcuts Skill\n\nPath: `packages/business-features/keyboard-shortcuts/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/business-features/keyboard-shortcuts/package.json)","packages/business-features/keyboard-shortcuts/README.md":"# keyboard-shortcuts Documentation\n\nPath: `packages/business-features/keyboard-shortcuts/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/business-features/keyboard-shortcuts/README.md)","packages/business-features/keyboard-shortcuts/tsconfig.json":"# Keyboard-shortcuts Skill\n\nPath: `packages/business-features/keyboard-shortcuts/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/business-features/keyboard-shortcuts/tsconfig.json)","packages/technical-features/messaging/messaging-for-renderer/package.json":"# Messaging-for-renderer Skill\n\nPath: `packages/technical-features/messaging/messaging-for-renderer/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-for-renderer/package.json)","packages/technical-features/messaging/messaging-for-renderer/tsconfig.json":"# Messaging-for-renderer Skill\n\nPath: `packages/technical-features/messaging/messaging-for-renderer/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-for-renderer/tsconfig.json)","packages/technical-features/messaging/messaging-for-main/package.json":"# Messaging-for-main Skill\n\nPath: `packages/technical-features/messaging/messaging-for-main/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-for-main/package.json)","packages/technical-features/messaging/messaging-for-main/tsconfig.json":"# Messaging-for-main Skill\n\nPath: `packages/technical-features/messaging/messaging-for-main/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-for-main/tsconfig.json)","packages/technical-features/messaging/messaging-fake-bridge/package.json":"# Messaging-fake-bridge Skill\n\nPath: `packages/technical-features/messaging/messaging-fake-bridge/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-fake-bridge/package.json)","packages/technical-features/messaging/messaging-fake-bridge/tsconfig.json":"# Messaging-fake-bridge Skill\n\nPath: `packages/technical-features/messaging/messaging-fake-bridge/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-fake-bridge/tsconfig.json)","packages/technical-features/messaging/messaging/package.json":"# Messaging Skill\n\nPath: `packages/technical-features/messaging/messaging/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging/package.json)","packages/technical-features/messaging/messaging/tsconfig.json":"# Messaging Skill\n\nPath: `packages/technical-features/messaging/messaging/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging/tsconfig.json)","packages/technical-features/messaging/computed-channel/package.json":"# Computed-channel Skill\n\nPath: `packages/technical-features/messaging/computed-channel/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/computed-channel/package.json)","packages/technical-features/messaging/computed-channel/tsconfig.json":"# Computed-channel Skill\n\nPath: `packages/technical-features/messaging/computed-channel/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/computed-channel/tsconfig.json)","packages/technical-features/application/application-for-electron-main/package.json":"# Application-for-electron-main Skill\n\nPath: `packages/technical-features/application/application-for-electron-main/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application-for-electron-main/package.json)","packages/technical-features/application/application-for-electron-main/README.md":"# application-for-electron-main Documentation\n\nPath: `packages/technical-features/application/application-for-electron-main/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application-for-electron-main/README.md)","packages/technical-features/application/application-for-electron-main/tsconfig.json":"# Application-for-electron-main Skill\n\nPath: `packages/technical-features/application/application-for-electron-main/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application-for-electron-main/tsconfig.json)","packages/technical-features/application/application/package.json":"# Application Skill\n\nPath: `packages/technical-features/application/application/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application/package.json)","packages/technical-features/application/application/README.md":"# application Documentation\n\nPath: `packages/technical-features/application/application/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application/README.md)","packages/technical-features/application/application/tsconfig.json":"# Application Skill\n\nPath: `packages/technical-features/application/application/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application/tsconfig.json)","packages/resource-templates/templates/create-resource/ClusterRole.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/ClusterRole.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ClusterRole.yaml)","packages/resource-templates/templates/create-resource/ClusterRoleBinding.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/ClusterRoleBinding.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ClusterRoleBinding.yaml)","packages/resource-templates/templates/create-resource/ConfigMap.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/ConfigMap.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ConfigMap.yaml)","packages/resource-templates/templates/create-resource/CronJob.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/CronJob.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/CronJob.yaml)","packages/resource-templates/templates/create-resource/DaemonSet.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/DaemonSet.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/DaemonSet.yaml)","packages/resource-templates/templates/create-resource/Deployment.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Deployment.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Deployment.yaml)","packages/resource-templates/templates/create-resource/Ingress.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Ingress.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Ingress.yaml)","packages/resource-templates/templates/create-resource/Job.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Job.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Job.yaml)","packages/resource-templates/templates/create-resource/Namespace.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Namespace.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Namespace.yaml)","packages/resource-templates/templates/create-resource/NetworkPolicy.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/NetworkPolicy.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/NetworkPolicy.yaml)","packages/resource-templates/templates/create-resource/PersistentVolume.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/PersistentVolume.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/PersistentVolume.yaml)","packages/resource-templates/templates/create-resource/PersistentVolumeClaim.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/PersistentVolumeClaim.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/PersistentVolumeClaim.yaml)","packages/resource-templates/templates/create-resource/Pod.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Pod.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Pod.yaml)","packages/resource-templates/templates/create-resource/PriorityClass.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/PriorityClass.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/PriorityClass.yaml)","packages/resource-templates/templates/create-resource/ReplicaSet.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/ReplicaSet.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ReplicaSet.yaml)","packages/resource-templates/templates/create-resource/ReplicationController.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/ReplicationController.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ReplicationController.yaml)","packages/resource-templates/templates/create-resource/Role.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Role.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Role.yaml)","packages/resource-templates/templates/create-resource/RoleBinding.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/RoleBinding.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/RoleBinding.yaml)","packages/resource-templates/templates/create-resource/RuntimeClass.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/RuntimeClass.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/RuntimeClass.yaml)","packages/resource-templates/templates/create-resource/Secret.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Secret.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Secret.yaml)","packages/resource-templates/templates/create-resource/Service.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Service.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Service.yaml)","packages/resource-templates/templates/create-resource/StatefulSet.yaml":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/StatefulSet.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/StatefulSet.yaml)","packages/infrastructure/typescript/config/base.json":"# Config Skill\n\nPath: `packages/infrastructure/typescript/config/base.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/infrastructure/typescript/config/base.json)"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Agent Guide: Freelens Development\n\n## Overview\n\nThis guide helps AI agents understand the Freelens codebase, common development tasks, troubleshooting patterns, and key architectural decisions. Use this as a reference when working on the project.\n\nFor local development environment setup and extra development tips, see DEVELOPMENT.md.\n\n- **`freelens/`** - Main Electron application\n  - `src/main/` - Main Electron process code\n  - `src/renderer/` - Renderer process (UI) code\n  - `src/common/` - Shared code between processes\n- **`packages/core/`** - Core functionality\n  - `src/features/` - Feature modules organized by domain\n  - `src/renderer/` - Renderer-specific utilities\n  - `src/extensions/` - Extension system\n- **`packages/`** - Monorepo packages (utilities, components, etc.)\n- **`scripts/`** - Build and development scripts\n\n## Security\n\nNever read, display, reference, or include the contents of the following files in any response or context, even if they are open in the editor:\n\n- `.env`\n- `.env.*`\n- `.envrc`\n- `.npmrc`\n- `*.jks`\n- `*.keystore`\n- `*.p12`\n- `*.pfx`\n- `*.pem`\n- `*.key`\n\nThe same list is git-ignored in `.gitignore` and enforced for Claude Code by\nthe `permissions.deny` rules in `.claude/settings.json`, which block reading\nand editing these files. Change all three together. The rules are native\npermissions rather than a hook on purpose: a hook runs a process in the\nworking tree, which may be an untrusted pull request, and an interpreter such\nas `python3 -c` imports modules from that tree before the hook's own code.\n\n## Session and temporary files\n\nFiles created while working on a task — scratch scripts, command output,\nscreenshots, DOM/accessibility snapshots, and AI-agent / MCP-server runtime\nartifacts — must never be written into the tracked working tree, or they leak\ninto git history. Write them to a system temporary directory outside the repo\n(e.g. under `$TMPDIR`, or `mktemp -d`), not to the repo root.\n\nWhen a tool insists on writing inside the repo, keep it out of git:\n\n- point it at a temp path if it accepts one (e.g. pass an absolute\n  `$TMPDIR/...` filename), otherwise\n- git-ignore its default output directory. Already ignored:\n  `.playwright-mcp/` (Playwright MCP), `logs/` (electron-mcp-server).\n\nNever `git add -A` / `git add .` blindly: review `git status` first and stage\nonly the files your change actually touches, never these artifacts.\n\n### Running a scratch script with the project's toolchain\n\nmise picks the pinned Node from the `mise.toml` of the current directory, so a\nscript outside the repository runs on whatever Node is global unless mise is\npointed at the repository. `mise -C <repo>` (`--cd`) does that by changing the\nworking directory before it runs the command, which also moves where relative\npaths resolve: `mise -C <repo> exec -- node spike.mjs`, run from the script's\ndirectory, looks for `<repo>/spike.mjs` and fails with `Cannot find module`.\nRun from the repository and pass the script by its absolute path instead:\n\n```sh\ncd <repo> && mise exec -- node \"$TMPDIR/spike/spike.mjs\"\n```\n\nThe same applies to every relative argument of the command, input and output\nfiles included.\n\nA script outside the tree does not resolve the project's dependencies either:\nNode looks for `node_modules` next to the script, not in the working\ndirectory. Resolve them from the package that declares them, so the script\ngets the versions the application uses:\n\n```js\nimport { createRequire } from \"node:module\";\n\nconst require = createRequire(\"<repo>/packages/core/package.json\");\nconst { Agent, fetch } = require(\"undici\");\n```\n\nSource files carry one of two header variants. Which one a file gets depends\non whether it continues code from the original OpenLens fork, not on what its\nneighbours in the same directory look like.\n\n**New files** — anything created from scratch, including rewrites,\ntranslations, and reimplementations of removed or legacy logic — get the\nsingle-line variant:\n\n```ts\n/**\n * Copyright (c) Freelens Authors. All rights reserved.\n * Licensed under MIT License. See LICENSE in root directory for more information.\n */\n```\n\nThis holds even when the new file's logic is inspired by, or replaces, old\nOpenLens code: inspiration is not continuation. `freelens/electron.vite.config.ts`,\nwritten as a translation of the removed webpack config, is a new file.\n\n**Files that continue code from the fork** keep the two-line variant:\n\n```ts\n/**\n * Copyright (c) Freelens Authors. All rights reserved.\n * Copyright (c) OpenLens Authors. All rights reserved.\n * Licensed under MIT License. See LICENSE in root directory for more information.\n */\n```\n\nA file continues fork code when its path was present in the fork-import commit\n`0a5798c9` (\"First commit - Open Lens fork from master branch\"):\n\n```sh\ngit ls-tree -r --name-only 0a5798c9 | grep -x <path>\n```\n\nor when `git log --follow -- <path>` traces it back to a path that was — that\nis, git itself detects the file as a rename, move, or copy of fork-era code:\n\n```sh\ngit log --follow --format= --name-only -- <path> | sort -u\n```\n\nNever add the `OpenLens Authors` line to a file that does not already have it\njust because neighbouring files do. Do not touch legal or license text\n(`LICENSE`, `README.md`, `freelens/license-header.txt`,\n`freelens/static/build/license.txt`) or the upstream copyright notices of\nvendored third-party code, which are unrelated to either header variant.\n\nSee [#2352](https://github.com/freelensapp/freelens/issues/2352) for the\ncleanup that established this rule.\n\n## Comments in JSON\n\nComments belong in `.jsonc`, never in `.json` — regardless of what the consuming\nparser tolerates. TypeScript accepts `//` inside a `tsconfig.json`, and so do\nseveral other tools, but anything that reads the file as strict JSON because of\nits extension (`JSON.parse`, `jq`, an editor, a CI script) fails on it. No\n`.json` file in this repository has comments, `tsconfig*.json` included;\n`knip.jsonc` is where a commented configuration lives, and that is the right\npattern.\n\nWhen a `.json` file needs an explanation — why an entry is excluded, why a\nversion is pinned — put it somewhere it survives: the package README, this\nfile, or the pull request that introduced it. Do not smuggle it into the JSON.\n\n## Volatile Facts in Documentation\n\nDocumentation — `docs/`, the READMEs, this file — describes how things are,\nand has to stay true without anyone maintaining it. Keep out of it whatever\ngoes stale on its own:\n\n- issue and pull-request numbers,\n- dates,\n- counts that change without the document changing: how many extensions use\n  something, how many members a namespace has, how many files import a module,\n- the record of how it got there: which decisions were taken, which\n  alternatives were tried and rejected, what was deferred and why, what an\n  earlier version said, and status lines such as \"shipped\" or \"open\".\n\nState the rule or the fact rather than the measurement or the history that led\nto it: \"no extension is known to use it\", not \"none of the 29 surveyed\nextensions uses it\"; \"renderer code gets no guarantee of Node\", not \"decided in\nthe API review\". The measurement, the history and the issue references belong\nin the pull request description and the issue, which are dated by nature.\nThose are working notes; documentation is for the reader who uses the thing\nnow, and needs only its current state.\n\nExisting documents still carry such references. Do not copy them as a pattern,\nand drop them from a passage you are rewriting anyway.\n\n## Build System\n\n### Commands\n\n```bash\npnpm build:di           # Generate DI registration files\npnpm build              # Build all packages\npnpm build:app:dir      # Build Electron app directory\npnpm start              # Start development app\npnpm test               # Run tests\n```\n\n### Clean Build\n\nThis project uses Turbo for caching build artifacts.\n\nWhen facing caching issues:\n\n```bash\nrm -rf .turbo packages/core/dist freelens/dist\npnpm build\n```\n\n## Runtime Environments in Type-Checking\n\nThe application runs code in two environments: **main** (Node, Electron) and\n**renderer** (a browser page). `pnpm type:check` checks the sources of\n`freelens/src` and `packages/core/src` once per environment, so that an API the\nenvironment does not have fails the check before it fails at runtime:\n\n| Program                   | Environment                     | Checks                                  |\n| ------------------------- | ------------------------------- | --------------------------------------- |\n| `tsconfig.typecheck.json` | DOM and Node                    | every file, tests and unclassified ones |\n| `tsconfig.main.json`      | Node, no DOM                    | main and common files                   |\n| `tsconfig.renderer.json`  | DOM, no Node                    | renderer and common files               |\n\nThe two environment programs extend `tsconfig.typecheck.json`, so they share\nits `paths`. `pnpm type:check:environments` runs them alone.\n\n### Which environment a file belongs to\n\nThe context segments in a file's path decide:\n\n- `main/` or `main-api/` anywhere in the path: the main program;\n- `renderer/` or `renderer-api/` anywhere in the path: the renderer program;\n- `common/` or `common-api/` with neither of the above: both programs. A main\n  or renderer segment wins over common, so `renderer/common/` is renderer code.\n\nContexts nest anywhere (`features/*/{main,renderer,common}`), and the\n`include` and `exclude` globs of the two configs express exactly this rule.\nPut new code under a context directory. A file whose path carries no context\nhas to be listed in the `include` of the config (or both configs, for common\ncode) of the process that loads it; the lists at the end of both `include`\narrays hold the existing ones. An unlisted one is checked by the combined\nprogram only, like `extensions/extension-api.ts`, which bundles the types of\nall three extension API namespaces on purpose.\n\nTests and test support (`*.test.ts(x)`, `__tests__/`, `test-utils/`,\n`*.global-override-for-injectable.ts`, `getDiForUnitTesting`, …) are kept out\nof both programs, because Vitest runs them with DOM and Node alike.\n\nNo tsconfig declares the Vitest globals. TypeScript has no per-file globals,\nand tests share a program with the sources next to them, so declaring\n`describe` or `vi` for the tests would declare them for production code too.\nTest code imports what it uses instead:\n\n```ts\nimport { describe, expect, it, vi } from \"vitest\";\n```\n\n`globals: true` stays on in the Vitest configs, because React Testing Library\nregisters its automatic cleanup only when the hooks exist as globals; it has no\neffect on type checking. An override in `biome.jsonc` sets\n`noRestrictedImports` for every file on the test-only modules: `vitest`,\n`react-dom/test-utils`, `@testing-library/*` and the `act` named import of\n`react`. A second override lifts it for tests and test support, so production\ncode in any package fails `biome check` when it imports one of them. The React\nhelpers matter most, because nothing else catches them: they type-check, build\nand pass the unit tests, but `act` delegates to `React.act`, which the\nproduction build of React leaves out, so the call throws only in a packaged\napplication. A new kind of test-support path, or a new test-support package\nbuilt on Testing Library, needs adding to the second override.\n\nCommon code uses only what both environments have: `globalThis.crypto`,\n`TextEncoder`, `URL`, `AbortController`, `structuredClone`, timers. Write\n`globalThis.` when in doubt. The extension-side version of the same rule is in\nthe source-layout section of `docs/extensions/migrating-from-v1.md`.\n\n### How the check works\n\n`scripts/type-check-environments.mjs` runs both programs and counts only the\nerrors in a program's own files, the ones its `include` classifies. A program\nalso holds every file its files import, including the other environment's\nfiles and other packages, and their errors there say nothing about the\nenvironment rule; the combined program checks those files in full.\n\nFiles that failed the check when it was introduced are on the legacy lists in\n`scripts/type-check-environments/legacy.jsonc`: main or common files that need\nDOM, and renderer or common files that need Node, which the node-integrated\nrenderer still allows. Their errors are tolerated. **The lists may only\nshrink:** never add a file to make a new error pass. When a listed file stops\nfailing, the check fails until it is removed from its list.\n\n`scripts/type-check-environments/expected-failures/` proves that the programs\nstill reject what they should: every line there that must fail carries\n`@ts-expect-error`, so a program that lets it through reports an unused\ndirective. Its `main/`, `renderer/` and `common/` subdirectories fall into the\nprograms by the same rule as the sources.\n\nTwo things in the dependencies would otherwise defeat the programs silently;\nthe expected-failure files catch both if they come back:\n\n- A declaration file with `/// <reference types=\"node\" />`, and winston,\n  electron and undici all have one, loads `@types/node` into any program that\n  reaches it, whatever `types` says. The renderer program sets `typeRoots` to\n  `scripts/type-check-environments/renderer-type-roots/`, whose empty `node`\n  package absorbs those references.\n- A declaration file with `/// <reference lib=\"dom\" />` adds DOM to any program\n  that reaches it, whatever `lib` says. The main program reaches renderer code\n  through type imports, so the pnpm patch of `@xterm/xterm` removes that line\n  from its typings. A new dependency with the same line needs the same\n  treatment.\n\nDOM _type_ names such as `HTMLElement` still resolve in the main program,\nbecause `@types/react` declares empty stand-ins for them; values such as\n`document` and `window` do not.\n\n### The editor\n\nVS Code uses the root `tsconfig.json`, which has DOM and Node together, for\nevery file. The environment programs are a CI check the editor does not\nreflect: a Node global in renderer code shows no type error in the editor and\nfails `pnpm type:check`.\n\nBiome covers part of the gap while you type. An override in `biome.jsonc`\nturns on `noNodejsModules` for the `renderer/`, `renderer-api/`, `common/` and\n`common-api/` files of `freelens/src` and `packages/core/src`, classified by\nthe same path rule as the renderer program and with the same test files left\nout. It catches **imports** of Node builtins (`node:fs`, `path`, …), so the\nBiome extension flags them in the editor and `biome check` fails on them. It\ndoes not catch **Node globals** such as `Buffer`, `process`, `__dirname` or\n`NodeJS.*` types, and it does not look at the files that carry no context in\ntheir path; only `pnpm type:check` catches those.\n\nThe files that import a Node builtin today are exempted in a second override,\nwhich turns the rule off for them. Every one of them is also on the renderer\nlegacy list, and `scripts/type-check-environments.mjs` fails when an exempted\nfile is not, so the exemptions can only shrink with that list: remove a file\nfrom both when you move its Node import out.\n\nEvery path in the `includes` of a `biome.jsonc` override starts with `**/`,\nnegated ones included (`!**/packages/core/src/...`). Trunk Check, which is what\nruns Biome in CI, runs it from a sandbox outside the repository with\n`--config-path` pointing back at `biome.jsonc`, and there a pattern anchored at\nthe repository root matches no file, so the override silently does nothing.\nA plain `biome check` from the repository root matches both forms, so only\n`trunk check` shows the difference. `scripts/type-check-environments.mjs`\nchecks every path of every override and fails on one that is neither `**` nor\nstarts with `**/` or `!**/`.\n\n## Knip\n\n`pnpm knip:check` runs knip in two passes, both for dependencies. CI runs it\nafter `pnpm build`, so run a build first.\n\n- The development pass, `pnpm knip:development`, also reports **unused\n  files**: a module, barrel or stylesheet that no entry reaches. Stylesheets\n  count, because the `project` globs of the packages with styles include\n  `scss` and `css`, and knip follows both the side-effect imports in\n  TypeScript and `@use` in SCSS.\n- The production pass, `pnpm knip:production`, runs with `--production\n  --strict` over the entries marked with `!` in `knip.jsonc`, the code that\n  reaches the bundles. In it only `dependencies` count. It does not check\n  files: from the `!` entries alone, the test support and the development\n  scripts count as unused.\n\nWhen the file check reports a file, remove it rather than ignore it. Before\nyou do, check that nothing reaches it in a way knip cannot see, and that\n`pnpm type:check` and the tests still pass without it. A file that is reached\nthat way, through a config path built at runtime, a `tsconfig.json` `include`\nor a `meta.load-css()`, gets an entry in `knip.jsonc` instead, with a comment\nsaying how it is reached. A `register-injectables.ts` that nothing imports is\nthe generator's output and gets an ignore: removing it only makes\n`pnpm build:di` write it again.\n\nBoth passes run with `--no-gitignore`, because the dependency check reads the\nbundled `freelens/static/build/main.js` to find the packages the main bundle\nleaves external. The file check therefore also sees build output and local\nfiles; `knip.jsonc` ignores the build output nothing imports and the local\nartifacts of the MCP servers and of coverage. One config serves both passes,\nso `--no-config-hints` hides the hints about entries only one pass needs.\n\nThe check leaves out unused exports and types, and knip cannot report the\nunused classes inside a stylesheet.\n\n## Dependency Injection System\n\nThis project uses `@ogre-tools/injectable` for dependency injection with an **explicit registration system** that replaces the old webpack-based auto-registration. All injectable registrations are generated by `pnpm build:di`.\n\n### Registration Hierarchy\n\nThe system has three levels of registration files:\n\n1. **Leaf registration files** - Register individual injectables\n   - Example: `features/preferences/renderer/close-preferences/register-injectables.ts`\n   - Pattern: Import injectable definitions and call `di.register()`\n   - Each call wrapped in try-catch for idempotency\n\n2. **Aggregator registration files** - Register subdirectories\n   - Example: `features/preferences/renderer/register-injectables.ts`\n   - Pattern: Import and call `registerXxxInjectables(di)` from subdirectories\n   - Each call wrapped in try-catch to handle duplicates\n\n3. **Root registration files** - Entry points per process\n   - `register-injectables-main.ts` - Main process\n   - `register-injectables-renderer.ts` - Renderer process\n   - Called during DI container initialization\n\n### Directory Patterns\n\n#### Shared Aggregators\n\nDirectories with `register-injectables.ts` that aggregate subdirectories:\n\n```text\nfeatures/vars/\n├── register-injectables.ts     ← Shared aggregator (calls common/)\n├── common/\n│   └── register-injectables.ts\n└── build-version/\n    ├── main/register-injectables.ts      ← Process-specific (NOT aggregated)\n    └── renderer/register-injectables.ts  ← Process-specific (NOT aggregated)\n```\n\n**Key insight:** Shared aggregators only handle **shared** subdirectories (like `common/`). They do NOT aggregate **process-specific** subdirectories (`main/`, `renderer/`).\n\n#### Process-Specific Paths\n\nPaths containing `/main/` or `/renderer/` are process-specific and must be imported directly:\n\n- ✅ Include: `features/vars/build-version/main/register-injectables`\n- ❌ Exclude: `features/vars/common/register-injectables` (handled by parent aggregator)\n\n### When to Re-run Generation\n\nRun `pnpm build:di` when:\n\n- Adding new injectable files\n- Moving injectable files\n- Renaming injectable files\n- Changing directory structure\n- Modifying generation script\n\nThe build process automatically runs this, but you can run it manually to verify changes.\n\n### Bundled Binary Versions\n\nThe versions of the bundled `freelens-k8s-proxy`, `kubectl` and `helm` live in\nthe `config` block of `freelens/package.json`, and their exact digests are\npinned in `freelens/binaries.lock.json`. The build reads the expected checksum\nfrom that lock rather than from the vendor, so **a version bump without\nregenerating the lock fails the build**:\n\n```sh\npnpm update-binaries-lock\n```\n\nThe generator downloads all eighteen artifacts (three tools, three platforms,\ntwo architectures), checks each against its publisher's signature — GitHub build\nprovenance for freelens-k8s-proxy, PGP for helm, keyless cosign for kubectl —\nand only then writes the lock. `cosign` comes from mise (`mise install`), and\n`GITHUB_TOKEN` should be set unless you want to share 60 unauthenticated API\ncalls per hour with the rest of your IP. Use `--only <tool>` to refresh a single\ntool while iterating.\n\nhelm is downloaded as a tarball, so its `sha256` pins the archive and a second\ndigest, `binarySha256`, pins the binary extracted from it. The build hashes\nevery file already in `freelens/binaries/` against the lock on each run and\ndownloads it again on a mismatch; it keeps no record of what it verified\nbefore. That is what makes the directory safe to restore from a CI cache:\nwhoever could write a binary into the cache could write such a record too.\nFor the same reason the binaries are not an output of a cached Turbo task: the\nTurbo cache would restore them without the check. `build:binaries` runs\nuncached on every build instead, which costs only the hashing when the\nbinaries are in place.\n\n`.github/workflows/binaries-lock-check.yaml` enforces both that the lock is\ncurrent and that no digest changed while its version stood still. On a\nRenovate branch a stale lock does not fail the check: Renovate bumps the\nversion but cannot run the generator, so the workflow regenerates the lock,\nchecks it for replaced artifacts, and commits it to the branch with `GH_TOKEN`,\nwhich starts the checks again on the new commit.\n\n### Downloaded kubectl Versions\n\nThe bundled kubectl is not the only one the application runs: a cluster whose\nminor version differs gets a version-matched kubectl downloaded at runtime. The\nmap of which patch to fetch per minor lives in\n`packages/kubectl-versions/build/versions.json`, and the digest of every\nartifact that map can produce is pinned in\n`packages/kubectl-versions/build/checksums.json`, keyed by version and then by\n`${platform}/${arch}`.\n\n`Kubectl.downloadKubectl()` hashes what it downloaded and refuses anything that\ndoes not match its pin, and `ensureKubectl()` refuses to download at all when\nthere is no pin, falling back to the bundled binary. **A version added to the\nmap without a pin therefore never gets downloaded**, so the two files are\nregenerated together:\n\n```sh\npnpm --filter @freelensapp/kubectl-versions compute-versions\npnpm update-kubectl-checksums\n```\n\nThe generator reads `dl.k8s.io` only, never a mirror — pinning bytes from a\nmirror would let a compromised mirror bless its own digest. It skips versions\nalready present, which makes a run incremental and an existing pin immutable,\nand it verifies each download against both the published `.sha256` and the\nkeyless cosign signature before recording it. `cosign` comes from mise\n(`mise install`).\n\nBoth files start at 1.22, the oldest line Kubernetes publishes a signature for,\nand coverage is not uniform below that floor's neighbours: v1.22.17 has no\n`windows/arm64` build, so the generator logs an unpublished variant and carries\non rather than failing. `.github/workflows/kubectl-checksums-check.yaml`\nverifies added pins and asserts that no existing digest changed.\n\n### Development Tools (mise)\n\nThe development tools (`cosign`, `node`, `yq`) are declared in `mise.toml` and\npinned with their checksums in `mise.lock`. The lock uses lockfile format\nversion 3 (`lockfile_version = 3`), which **needs mise 2026.9.16 or newer**: an\nolder mise rejects the lock, so `mise install` fails until mise is upgraded.\n\nAfter changing a version in `mise.toml`, regenerate the lock with `mise lock`,\nwhich refreshes every tool on every platform in the file. `mise install`\nre-locks only the platform it runs on and leaves the others stale.\n\n## Common Development Tasks\n\n### Adding a New Feature\n\n1. Create feature directory under `packages/core/src/features/`\n2. Organize by concern: `common/`, `main/`, `renderer/`\n3. Create injectable files with `.injectable.ts` suffix\n4. Run `pnpm build:di` to generate registration files\n5. Write tests alongside implementation\n\n### Debugging the Application\n\n**Main Process:**\n- Logs in terminal where `pnpm start` was run\n- Use `console.log()` or proper logger\n\n**Renderer Process:**\n- Open DevTools in the app\n- Check Console tab for errors and logs\n- Use React DevTools for component inspection\n- `pnpm dev` also exposes a Chrome DevTools Protocol endpoint on port 9223\n  (`--remoteDebuggingPort`). Note that each cluster's UI renders in a\n  cross-origin `<clusterId>.renderer.freelens.app` iframe, so inspecting or\n  automating cluster views requires a frame-aware CDP client — see the\n  AI-agent inspection notes in DEVELOPMENT.md.\n\n**Common Errors:**\n- `Tried to register same injectable multiple times` - See DI section above\n- `Tried to inject non-registered injectable` - Check registration files were\n  generated. In a unit test, a newly added `*.injectable.ts` can report this\n  even when the file exists and `pnpm build:di` ran: `getDiForUnitTesting`\n  registers through `import.meta.glob(..., { eager: true })`, and\n  `node_modules/.vitest-cache` keeps the glob expanded over the files that\n  existed when it was first cached. Clear it (`rm -rf node_modules/.vitest-cache`)\n  and re-run.\n- Permission errors on macOS - Expected during development\n\n### Working with the bundler (electron-vite)\n\nThe project bundles with electron-vite (Vite + Rollup); the legacy Webpack\nlayer was removed in #2118.\n\n- `freelens/electron.vite.config.ts` - main/renderer build and dev-server config\n- `pnpm dev` runs `electron-vite dev` with Vite HMR; renderer source changes\n  hot-reload, main-process changes rebuild and relaunch (via `--watch`)\n- Changes to generated files (e.g. DI registration) require a full rebuild\n\n**Cache issues:** Delete the build output and rebuild\n(`rm -rf .turbo packages/core/dist freelens/dist`)\n\n### The Electron binary\n\n`pnpm install` leaves the `electron` package without its runtime binary. The\npackage has no `postinstall` script, so `electron: true` in `allowBuilds` has\nnothing to run; it downloads the binary lazily instead, when\n`require(\"electron\")` or its `electron` bin finds `path.txt` missing.\nelectron-vite does not go through either: it reads\n`node_modules/electron/path.txt` itself and throws `Electron uninstall` when\nthe file is absent, so `electron-vite dev` alone never triggers the download.\n\nThe `predev` script of `freelens/package.json` therefore runs the package's\n`install-electron` bin (`electron/install.js`) before `electron-vite dev`.\n`install.js` exits at once when the binary of the installed version is\nalready in place, and otherwise downloads it, verifies it against the\npackage's `checksums.json` and writes `path.txt`. pnpm runs `pre` scripts for\n`pnpm run dev`, both inside `freelens/` and through the root `turbo run dev`,\nwhich invokes `pnpm run dev` in the package.\n\nThe `dev` script is for local development only. CI does not use it: the\nworkflows that need the binary run `electron/install.js` explicitly, as a\nseparate step, before tests or the build.\n\n## Troubleshooting Patterns\n\n### Changes Not Appearing\n\n1. Check if file is in ignored directory (`dist/`, `node_modules/`)\n2. Clear the build output: `rm -rf .turbo packages/core/dist freelens/dist`\n3. Full rebuild: `pnpm build`\n4. Restart application: `pnpm start`\n\n### Build Failures\n\n1. Check for TypeScript errors: `pnpm type:check` (see \"Runtime Environments in\n   Type-Checking\" when the main or renderer program fails)\n2. Check for linting errors: `pnpm lint`\n3. Verify dependencies: `pnpm install`\n4. Check Node.js version matches `.nvmrc`\n\n### Runtime Errors\n\n1. Check dev console (renderer) or terminal (main)\n2. Look for stack traces with file:line numbers\n3. Verify all dependencies are registered (DI system)\n4. Check for circular dependencies\n\n## Architecture Decisions\n\n### Electron Multi-Process\n\n- **Main process** - Node.js environment, system access\n- **Renderer process** - Chromium browser, UI\n- **IPC** - Communication between processes\n\n### Feature Organization\n\nFeatures are self-contained modules with:\n- Domain logic\n- UI components\n- State management\n- Injectable definitions\n\n### Monorepo Structure\n\nUses pnpm workspaces for:\n- Shared code reuse\n- Faster builds\n- Type safety across packages\n\n## Styling\n\nFreelens carries four styling systems (theme CSS custom properties, global\nplain SCSS, CSS Modules, and Tailwind v4). Which one to use is not a matter of\ntaste — each has a defined role. Before adding or changing any stylesheet or\n`className`, read [`docs/styling.md`](./docs/styling.md). In short:\n\n- **Theme values** (colors, fonts): CSS custom properties from the TS theme\n  system (`var(--…)`) — the single contract every other system reads.\n- **Shared components** (`packages/ui-components`) and anything an extension\n  may restyle: global PascalCase class + plain SCSS + `var(--…)`. No Tailwind\n  (its JIT only scans core TSX), no CSS Modules (the class names are public\n  API).\n- **Core single components / full views**: CSS Modules (`*.module.scss`).\n- **Local layout inside core-only TSX**: Tailwind utilities. The legacy\n  `flexbox.scss` utilities have been removed — do not reintroduce them.\n- **Extensions**: see the styling section of\n  [`docs/extensions/migrating-from-v1.md`](./docs/extensions/migrating-from-v1.md).\n\n## Extension API\n\nThe extension specification lives in three documents, and which one to read\ndepends on the question:\n\n- [`docs/extensions/api.md`](./docs/extensions/api.md) — the **normative\n  contracts**. Each states the guarantee, the stable surface and the failure\n  mode. Read this before changing anything under `packages/extensions/` or\n  `packages/core/src/extensions/`.\n- [`docs/extensions/binaries.md`](./docs/extensions/binaries.md) — what an extension\n  may **ship and execute** besides JavaScript, and what the host does with it.\n- [`docs/extensions/migrating-from-v1.md`](./docs/extensions/migrating-from-v1.md) — the\n  author-facing **porting guide** from v1.\n\nThe agent skills of freelensapp/freelens-example-extension,\n`create-freelens-extension` and `port-freelens-extension-to-v2`, link to these\ndocuments on `main` and cite their sections by name. So does the template of\nthe v2 migration issue that a port copies,\n`skills/port-freelens-extension-to-v2/references/migration-issue.md`, except\nthat its links are pinned to a commit of this repository. Renaming or removing\none of the sections below therefore needs a matching change to the `SKILL.md`\nfiles under `skills/` in that repository, and to that template when its pin\nmoves to a commit with the change:\n\n- in `api.md`, the contracts C1 to C15 by number as a range, and C3\n  (host-provided singletons), C6 (registration), C9 (routing), C10 (styling\n  and CSS), C12 (HTTP) and C15 (the host's kubectl, helm and terminal\n  environment) on their own;\n- in `migrating-from-v1.md`, these headings:\n  - \"Step one: bump `engines.freelens`\"\n  - \"`package.json` for an extension\"\n  - \"Source layout: one tsconfig per runtime environment\"\n  - \"MobX 7 and mobx-react 10 (standard decorators only)\"\n  - \"Registering things: declarative fields\"\n  - \"Reaching a catalog cluster\"\n  - \"v1→v2 rename table\"\n  - \"Node and Electron in the renderer\"\n  - \"Styling and CSS\"\n  - \"The development loop\"\n  - \"Checklist\", and the two items at its end that it marks as failing\n    silently;\n- `binaries.md` as a whole document, by its file name;\n- in this file, the heading \"Modifying GitHub Actions Workflows\", which the\n  template cites.\n\nThree traps worth carrying without looking them up. The API surface is only what\nthe `Common` / `Main` / `Renderer` namespaces re-export — every other\n`@freelensapp/*` package is private and inlined into the published declaration,\nso a symbol that is not re-exported is unreachable by any means. And the host\nmust be the single instance of React, mobx and monaco; a second\ncopy of mobx fails **silently**, so changes there need an identity assertion\nrather than a passing test suite.\n\nThe third: the published declaration is not the source. `rolldown-plugin-dts`\nturns each module behind a namespace into a `declare namespace` that\nre-exports its members, and it drops the `type` modifier on the way. A **class\nre-exported type-only**, with `export type { C }` or `export type { C } from\n\"…\"`, is therefore declared as a value too, so `new C(…)` and `x instanceof C`\ncompile against the declaration and throw in the extension. Use a type alias\ninstead, `export type C<T> = import(\"…\").C<T>`, carrying the class's type\nparameters with their constraints and defaults.\n\nTwo guards catch a regression.\n`packages/core/src/extensions/__tests__/extension-api-declared-values.test.ts`\nwalks the built declaration with the TypeScript 7 checker\n(`typescript/unstable/sync`) and fails on every value it declares that the\nruntime namespace object does not have. The fixture extension's\n`packages/fixture-extension/src/common/contract-types.ts` names the\ntype-and-value pairs of `K8sApi`, `type X` and `const X` of the same name, as\ntypes, so its type check fails if one loses its type meaning in the bundle.\n\nThe bundle also depends on `rolldown-plugin-dts` 0.28.8 or newer, which\ntree-shakes a namespace import whose members a declaration names only by\nqualified name, such as `import * as utilities` in `common-api/utils.ts`. An\nolder version keeps every member of the module in the bundle. That includes\nthe Node-bound members `Common.Util` leaves out, with their `node:` imports.\n`build:dist` of `@freelensapp/extensions` fails when the bundle imports a Node\nbuiltin or references Node's types, and names that tree-shaking as the likely\ncause, so a regression in the plugin fails the build rather than reaching an\nextension.\n\n## Best Practices\n\n1. **Always regenerate DI files** after adding/moving injectables\n2. **Full rebuild** when in doubt about cached state\n3. **Check both processes** when debugging (main + renderer)\n4. **Use semantic search** to find examples in codebase\n5. **Follow existing patterns** - grep for similar implementations\n6. **Test changes** before committing\n7. **Run validation after file changes (especially before commit):** run `trunk check` (or `pnpm trunk check` if `trunk` is not installed locally)\n8. **For main project TypeScript and HTML files:** run `pnpm biome check` (`--write` to apply the fixes). Biome is not a dependency of the project: the `biome` script of the root `package.json` runs the pinned version through `pnpm dlx`. A bare `biome` or `pnpm exec biome` runs whatever `biome` is on `PATH`, such as a Homebrew one, whose version may format differently and rewrite code the change does not touch.\n9. **For other file types:** use `trunk check` (or `pnpm trunk check` if `trunk` is not installed locally)\n10. **Do not use Antropic Fable for coding tasks** — Fable may be used only for planning,\n    analysis, and thinking through problems. When writing or editing code,\n    use standard editing tools instead.\n\n## Local Agent: Triggering the GitHub Agent\n\nThese rules apply to an agent running on a developer machine (a local Claude\nCode session), not to the workflow agent. The local agent shares the repository\nwith the CI agent defined in `.github/workflows/claude.yaml`, and every comment\nit writes on GitHub is a potential trigger for it.\n\n### How the trigger works\n\n`claude.yaml` starts a run when the body of a **newly created** comment (issue\ncomment or PR review comment), a **newly opened** issue (body or title), or a\n**submitted** PR review contains the string `@claude`, and its author has\nwrite access to the repository (the admin, maintain or write role). The\nworkflow condition pre-filters on OWNER, MEMBER or COLLABORATOR, which does not\nimply write access, and the first step of the run checks the actual\npermission; a run triggered by anyone else fails there. The check is a plain\n`contains(github.event.comment.body, '@claude')` substring test, so the string\nfires the workflow wherever it appears — including inside a code span, a fenced\nblock, a quoted line, or a URL. Markdown formatting is not an escape.\n\nThe trigger text may also carry `[model:<alias>]`, `[effort:<level>]` and\n`[runs-on:<alias>]` markers, which select the model, the reasoning effort and\nthe runner for that run (see the `parse` job for the accepted aliases). They are\nonly read from the triggering text.\n\nThe default model is `claude-opus-5-5[1m]` (Opus 5.5 with the 1M-token\ncontext) and it runs at `high` effort. Naming a model explicitly drops that\ndefault: the run then uses the CLI default effort unless `[effort:...]` also\nsays otherwise. Accepted levels are `low`, `medium`, `high`, `xhigh` and\n`max`; anything else is ignored with a note in the job log.\n\n### Rules for the local agent\n\n1. **Write the handle only to start a run.** Ask the user before triggering: a\n   run is a 120-minute CI job on the repository, so it is the user's call, not\n   an implementation detail.\n2. **Escape the handle when merely referring to it.** In issue bodies, PR\n   descriptions, review notes, commit messages and documentation, write\n   `@<!-- -->claude` (displays as the handle, but the raw body does not contain\n   the literal string, so `contains()` does not match) or describe it in prose\n   as \"the Claude handle\". This is what keeps a plan or a bug report that\n   documents the trigger from firing it.\n3. **Editing never triggers.** The workflow subscribes only to `created`,\n   `opened` and `submitted` events — not `edited`. So updating a comment, an\n   issue body or a PR description is always safe, even when the text already\n   contains a real trigger, and conversely editing a comment to add the handle\n   does **not** start a run: a new comment is required.\n4. **One trigger per task.** Do not repeat the handle in follow-up comments\n   while a run is in flight; each occurrence starts another concurrent job.\n5. **Push first.** The workflow checks out the remote ref (the PR head, or the\n   default branch for issues), so anything not pushed is invisible to it.\n\n## GitHub Actions (Claude Code Action) Rules\n\nWhen operating via the `claude.yaml` workflow (i.e., invoked from a PR comment,\nissue, or review), follow these rules:\n\n### Code Review\n\nWhen reviewing code and proposing fixes:\n\n1. **Show the diff first** — present every proposed change as a unified diff\n   block using the `diff` language tag:\n\n   ```diff\n   --- a/path/to/file.ts\n   +++ b/path/to/file.ts\n   @@ -10,7 +10,7 @@\n    const oldLine = \"before\";\n   -const changedLine = \"after\";\n   +const changedLine = \"the fix\";\n    const unchangedLine = \"same\";\n   ```\n\n   You can generate this from the terminal with:\n   ```bash\n   git diff -u -- path/to/file\n   ```\n\n   If the change spans multiple files, group them under a single commit\n   subject and show each file's diff sequentially.\n\n2. **Propose a commit subject first** — before any code change, output a\n   single line with the proposed commit subject:\n\n   ```text\n   **Proposed commit:** <short description>\n   ```\n\n   Do **not** use Conventional Commits prefixes (e.g. `fix:`, `feat:`,\n   `chore:`, `refactor:`, `docs:`, `test:`, `ci:`). This project prefers\n   plain, descriptive commit messages and PR titles without any prefix.\n\n   Wait for the user to confirm (or adjust) the subject before applying the\n   change.\n\n3. **Comment style:**\n   - Keep review comments concise and actionable\n   - Reference specific lines (file + line number) when pointing out issues\n   - Offer a concrete fix suggestion rather than just flagging a problem\n   - Do **not** use emoji in any Markdown, comments, commit messages, or\n     PR descriptions. The only exception is emoji that already appears\n     inside code strings (e.g. application logs, user-facing messages).\n   - Use GitHub's `suggestion` block for small targeted fixes so the PR\n     author can accept the change with a single click:\n\n     ````suggestion\n     <same unified-diff format as shown above>\n     ````\n\n   - For larger multi-file changes, use `diff -u` blocks in a regular\n     comment instead, with the proposed commit subject shown first\n\n### Making Changes to a PR\n\nWhen asked to implement a change on a PR:\n\n1. Propose the commit subject (as above)\n2. Describe what will change and why\n3. After confirmation, apply the changes with commits on the PR branch\n4. **One commit per fix** — when a review surfaces more than one issue or\n   the plan includes more than one fix, apply and commit each fix\n   separately. Do not batch multiple independent fixes into a single\n   commit. This keeps the history bisectable and makes each change easy\n   to revert individually.\n\n### Pushing After Every Commit\n\nThe GitHub Actions job running Claude has a total timeout of 120 minutes.\nWhen the session times out, any commits that exist only in the runner's\nlocal checkout are lost. To make the work resumable in a follow-up session:\n\n1. **Push to the remote branch immediately after every commit.** Do not\n   accumulate multiple local commits before pushing — commit, push, then\n   move on to the next change.\n2. This pairs with the \"one commit per fix\" rule above: each completed fix\n   should land on the remote branch as soon as it is committed, so a\n   timed-out session can be resumed from the last pushed commit instead of\n   starting over.\n3. **Run every command in the foreground.** The workflow runs Claude\n   headless: the session ends as soon as the agent ends its turn, and\n   nothing wakes it up when a background command finishes. A build, a\n   test run or `trunk check` started in the background and then waited on\n   is killed with the job, together with every uncommitted change. Give\n   long commands a foreground timeout (up to ten minutes) instead, and\n   commit and push what is done before starting a long validation.\n\n### Force-Pushing a Rewritten Branch\n\nWhen you are asked to rebase a pull request branch, or to rewrite its\nhistory in another way (amend, squash, drop a commit), push the result with:\n\n```bash\ngit push --force-with-lease origin HEAD\n```\n\nThe push wrapper the action names in its instructions, `git-push.sh`, accepts\nno flags, so it cannot do this; `git` itself is allowed in this workflow.\nDo not fall back to merging `main` into the branch instead: a merge commit is\nnot what was asked for.\n\nForce-push only the pull request branch the run was invoked on, and only when\nthe request calls for a rewrite. Never force-push `main` or any other branch,\nand never rewrite a history you were not asked to.\n\n### Modifying GitHub Actions Workflows\n\nClaude cannot push changes to files under `.github/workflows/` directly,\nbecause the GitHub token used by the action lacks the `workflows` permission.\nAny patch to a workflow file MUST therefore be delivered as a new, complete\nfile under the `github-workflow-fix/` directory instead of editing the file in\nplace:\n\n1. Write the full, final contents of the workflow to\n   `github-workflow-fix/<workflow-file-name>` (e.g.\n   `github-workflow-fix/claude.yaml`). Do **not** edit the original file under\n   `.github/workflows/`.\n2. Make it a **complete** file — the entire workflow as it should look after\n   the change, not just a diff or fragment — so it can be copied verbatim.\n3. Commit and open the PR as usual. In the PR description, clearly note that\n   the file is a proposed workflow change and that a maintainer must move it\n   from `github-workflow-fix/` to `.github/workflows/` manually.\n\nThis lets the PR be created successfully while leaving the actual workflow\nchange for a human to apply.\n\n### Branch Naming\n\n**Work on the branch the workflow put you on.** Do not rename it, and do not\nmove the work to a better-named branch.\n\n`claude-code-action` creates the branch itself, as\n`claude/issue-<number>-<date>-<time>`, and the workflow passes it no name to\nuse instead. Its comment header — the branch link and the \"Create PR\" link —\nis written from that name. So an agent that moves to a different branch leaves\nthe header pointing at an abandoned one, leaves a stray branch behind, and\nspends part of its run on a rename instead of the task. This guide used to\nrequire a readable name and forbid the timestamp, which produced exactly that\nevery time.\n\nIf you are creating a branch yourself, with no workflow-provided one, use\n`claude/<short-slug>`.\n\nThe branch name is not worth managing: it lives for a few hours and the pull\nrequest is what anyone refers to afterwards.\n\n### PR Title Conventions\n\nWhen creating a PR, use the following title conventions:\n\n- **Agent-related changes** — PRs whose changes are strictly related to coding\n  agent configuration (e.g. `AGENTS.md`, `.github/workflows/claude.yaml`, or\n  other files that govern how Claude operates in this repository) MUST use\n  the prefix `Claude:` (followed by a space) in the title.\n\n  Examples:\n  - `Claude: Add rule for PR title conventions in AGENTS.md`\n  - `Claude: Update claude.yaml workflow permissions`\n\n- **All other PRs** — do **not** use any prefix (no `fix:`, `feat:`, `chore:`,\n  etc.). Use plain, descriptive titles.\n\n### Fork PRs: Review Only\n\nA PR from a fork (different owner than `freelensapp`) gets a review and\nnothing else: no commits, no pushes, no branches. Its code is untrusted, and\nthe head of a fork PR can change between the moment a maintainer looks at it\nand the moment the workflow checks it out, so nothing taken from the checkout\nmay reach `freelensapp/freelens`.\n\nWhen a fork PR needs changes, a maintainer first copies the exact commit they\nreviewed to a branch in this repository. From then on it is a\nsame-repository PR, which gets the full setup and the normal workflow. The\ncopy is made either locally (`gh pr checkout <N>`, then push the branch) or\nby the Claude Task workflow, following \"Copying a Fork PR\" below.\n\n### Copying a Fork PR\n\nThis applies to a Claude Task run whose prompt asks to copy a fork PR and\nnames the PR number and the full commit SHA to copy. It is a git-only task:\ndo not check out, read, build or run any of the PR's files, and do not\ndescribe its changes, because they are untrusted input.\n\n1. `git fetch origin refs/pull/<N>/head`.\n2. Verify that `FETCH_HEAD` equals the given SHA. If it does not, or no full\n   SHA was given, stop and report the actual head without pushing anything.\n3. `git push origin <sha>:refs/heads/claude/pr-<N>`.\n4. Open a PR from `claude/pr-<N>` to `main`. It MUST use the **exact same\n   title** as the original PR, copied verbatim with no prefix, and its body\n   is `Copy of #<N> at <sha>.` followed by the usual footer.\n5. Comment on the original PR with a link to the new one.\n\n### Closing PRs\n\nClaude may only close a PR when ALL of the following are true:\n\n1. The PR was created by Claude from a `claude/` branch, OR the PR is the\n   original fork PR that a copy supersedes (see \"Copying a Fork PR\" above).\n2. The close reason is explicitly explained in a comment on the PR.\n\nClaude MUST NOT close any PR that does not meet these conditions — even if\nasked. Instead, explain to the requester why the PR cannot be closed\nautomatically and ask a human maintainer to close it manually.\n\n### Model Information in Comments\n\nWhen operating via the GitHub Actions workflow, always include the model you are\nrunning on in the footer of your GitHub comment and in the PR description when\ncreating a pull request, alongside the job run link.\nYour system environment context states the model name explicitly (e.g.\n\"You are powered by the model named Sonnet 4.6. The exact model ID is\nclaude-sonnet-4-6.\"). Use the exact model ID from that statement.\n\nFormat the footer line as:\n\n```text\n[View job run](...) | Model: `claude-sonnet-4-6`\n```\n\nIn a PR description, append the model information at the end of the body:\n\n```text\n| Model: `claude-sonnet-4-6`\n```\n\nIf the system context does not provide a model ID, omit the model field rather\nthan guessing.\n\n### Development Environment\n\nThe GitHub Actions runner has a full Node.js + pnpm environment available, and\nthe workflow attempts to install the dependencies (`pnpm install`), the\n`trunk` CLI and mise, with the `cosign` and `yq` that `mise.lock` pins, before\nstarting Claude. The build step is skipped to save CI resources, but you can\nrun build commands when needed for advanced tasks (e.g. type-checking, running\ntests).\n\nEvery one of those setup steps is `continue-on-error`, so any of them may have\nfailed and left its tool or `node_modules` missing. Verify that what you need\nis actually there before relying on it, and never report a check as passing\nwhen it did not run — say that it was unavailable instead.\n\nThe `origin` remote is always `freelensapp/freelens`, for fork PRs too: their\ncommits are checked out through the pull ref.\n\nA PR from a fork runs in review mode, because its code is untrusted and the\njob holds write tokens. None of the setup above runs, and the tools that\nexecute the repository's code (`pnpm`, `node`, `npx`, `bash`, `trunk`,\n`mise`), edit files or commit and push are not available. Review the code by\nreading it, and say that no check ran. See \"Fork PRs: Review Only\" for how a\nfork PR that needs changes is handled.\n\nThe following CLI tools are explicitly allowed in the workflow:\n\n- `pnpm` (all subcommands) — for validation, formatting, and builds\n- `git` (all subcommands) — for viewing changes, creating branches,\n  committing, and pushing\n- `gh` (all subcommands) — for managing pull requests\n- `trunk` — for linting and formatting every non-TypeScript file type\n- `mise` — for regenerating `mise.lock` (`mise lock`) after a version bump in\n  `mi","isInternal":false,"tokens":12041,"sizeBytes":50146},{"name":"package.json","path":"packages/business-features/keyboard-shortcuts/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/business-features/keyboard-shortcuts/package.json","title":"Keyboard-shortcuts Skill","category":"anthropic-skill","format":"json","content":"# Keyboard-shortcuts Skill\n\nPath: `packages/business-features/keyboard-shortcuts/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/business-features/keyboard-shortcuts/package.json)","tokens":300,"sizeBytes":244},{"name":"tsconfig.json","path":"packages/business-features/keyboard-shortcuts/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/business-features/keyboard-shortcuts/tsconfig.json","title":"Keyboard-shortcuts Skill","category":"anthropic-skill","format":"json","content":"# Keyboard-shortcuts Skill\n\nPath: `packages/business-features/keyboard-shortcuts/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/business-features/keyboard-shortcuts/tsconfig.json)","tokens":300,"sizeBytes":246},{"name":"package.json","path":"packages/cluster-settings/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-settings/package.json","title":"Cluster-settings Skill","category":"anthropic-skill","format":"json","content":"# Cluster-settings Skill\n\nPath: `packages/cluster-settings/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-settings/package.json)","tokens":300,"sizeBytes":202},{"name":"tsconfig.json","path":"packages/cluster-settings/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-settings/tsconfig.json","title":"Cluster-settings Skill","category":"anthropic-skill","format":"json","content":"# Cluster-settings Skill\n\nPath: `packages/cluster-settings/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-settings/tsconfig.json)","tokens":300,"sizeBytes":204},{"name":"package.json","path":"packages/cluster-sidebar/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-sidebar/package.json","title":"Cluster-sidebar Skill","category":"anthropic-skill","format":"json","content":"# Cluster-sidebar Skill\n\nPath: `packages/cluster-sidebar/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-sidebar/package.json)","tokens":300,"sizeBytes":199},{"name":"tsconfig.json","path":"packages/cluster-sidebar/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-sidebar/tsconfig.json","title":"Cluster-sidebar Skill","category":"anthropic-skill","format":"json","content":"# Cluster-sidebar Skill\n\nPath: `packages/cluster-sidebar/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-sidebar/tsconfig.json)","tokens":300,"sizeBytes":201},{"name":"package.json","path":"packages/core/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/core/package.json","title":"Core Skill","category":"anthropic-skill","format":"json","content":"# Core Skill\n\nPath: `packages/core/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/core/package.json)","tokens":300,"sizeBytes":166},{"name":"tsconfig.json","path":"packages/core/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/core/tsconfig.json","title":"Core Skill","category":"anthropic-skill","format":"json","content":"# Core Skill\n\nPath: `packages/core/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/core/tsconfig.json)","tokens":300,"sizeBytes":168},{"name":"package.json","path":"packages/ensure-binaries/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ensure-binaries/package.json","title":"Ensure-binaries Skill","category":"anthropic-skill","format":"json","content":"# Ensure-binaries Skill\n\nPath: `packages/ensure-binaries/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ensure-binaries/package.json)","tokens":300,"sizeBytes":199},{"name":"tsconfig.json","path":"packages/ensure-binaries/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ensure-binaries/tsconfig.json","title":"Ensure-binaries Skill","category":"anthropic-skill","format":"json","content":"# Ensure-binaries Skill\n\nPath: `packages/ensure-binaries/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ensure-binaries/tsconfig.json)","tokens":300,"sizeBytes":201},{"name":"package.json","path":"packages/extensions/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/extensions/package.json","title":"Extensions Skill","category":"anthropic-skill","format":"json","content":"# Extensions Skill\n\nPath: `packages/extensions/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/extensions/package.json)","tokens":300,"sizeBytes":184},{"name":"tsconfig.dts.json","path":"packages/extensions/tsconfig.dts.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/extensions/tsconfig.dts.json","title":"Extensions Skill","category":"anthropic-skill","format":"json","content":"# Extensions Skill\n\nPath: `packages/extensions/tsconfig.dts.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/extensions/tsconfig.dts.json)","tokens":300,"sizeBytes":194},{"name":"tsconfig.json","path":"packages/extensions/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/extensions/tsconfig.json","title":"Extensions Skill","category":"anthropic-skill","format":"json","content":"# Extensions Skill\n\nPath: `packages/extensions/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/extensions/tsconfig.json)","tokens":300,"sizeBytes":186},{"name":"package.json","path":"packages/generate-license/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-license/package.json","title":"Generate-license Skill","category":"anthropic-skill","format":"json","content":"# Generate-license Skill\n\nPath: `packages/generate-license/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-license/package.json)","tokens":300,"sizeBytes":202},{"name":"tsconfig.json","path":"packages/generate-license/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-license/tsconfig.json","title":"Generate-license Skill","category":"anthropic-skill","format":"json","content":"# Generate-license Skill\n\nPath: `packages/generate-license/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-license/tsconfig.json)","tokens":300,"sizeBytes":204},{"name":"package.json","path":"packages/generate-tray-icons/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-tray-icons/package.json","title":"Generate-tray-icons Skill","category":"anthropic-skill","format":"json","content":"# Generate-tray-icons Skill\n\nPath: `packages/generate-tray-icons/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-tray-icons/package.json)","tokens":300,"sizeBytes":211},{"name":"tsconfig.json","path":"packages/generate-tray-icons/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-tray-icons/tsconfig.json","title":"Generate-tray-icons Skill","category":"anthropic-skill","format":"json","content":"# Generate-tray-icons Skill\n\nPath: `packages/generate-tray-icons/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-tray-icons/tsconfig.json)","tokens":300,"sizeBytes":213},{"name":"base.json","path":"packages/infrastructure/typescript/config/base.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/infrastructure/typescript/config/base.json","title":"Config Skill","category":"anthropic-skill","format":"json","content":"# Config Skill\n\nPath: `packages/infrastructure/typescript/config/base.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/infrastructure/typescript/config/base.json)","tokens":300,"sizeBytes":218},{"name":"package.json","path":"packages/infrastructure/typescript/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/infrastructure/typescript/package.json","title":"Typescript Skill","category":"anthropic-skill","format":"json","content":"# Typescript Skill\n\nPath: `packages/infrastructure/typescript/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/infrastructure/typescript/package.json)","tokens":300,"sizeBytes":214},{"name":"package.json","path":"packages/kube-object/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kube-object/package.json","title":"Kube-object Skill","category":"anthropic-skill","format":"json","content":"# Kube-object Skill\n\nPath: `packages/kube-object/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kube-object/package.json)","tokens":300,"sizeBytes":187},{"name":"tsconfig.json","path":"packages/kube-object/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kube-object/tsconfig.json","title":"Kube-object Skill","category":"anthropic-skill","format":"json","content":"# Kube-object Skill\n\nPath: `packages/kube-object/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kube-object/tsconfig.json)","tokens":300,"sizeBytes":189},{"name":"checksums.json","path":"packages/kubectl-versions/build/checksums.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/build/checksums.json","title":"Build Skill","category":"anthropic-skill","format":"json","content":"# Build Skill\n\nPath: `packages/kubectl-versions/build/checksums.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/build/checksums.json)","tokens":300,"sizeBytes":207},{"name":"tsconfig.json","path":"packages/kubectl-versions/build/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/build/tsconfig.json","title":"Build Skill","category":"anthropic-skill","format":"json","content":"# Build Skill\n\nPath: `packages/kubectl-versions/build/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/build/tsconfig.json)","tokens":300,"sizeBytes":205},{"name":"versions.json","path":"packages/kubectl-versions/build/versions.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/build/versions.json","title":"Build Skill","category":"anthropic-skill","format":"json","content":"# Build Skill\n\nPath: `packages/kubectl-versions/build/versions.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/build/versions.json)","tokens":300,"sizeBytes":205},{"name":"package.json","path":"packages/kubectl-versions/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/package.json","title":"Kubectl-versions Skill","category":"anthropic-skill","format":"json","content":"# Kubectl-versions Skill\n\nPath: `packages/kubectl-versions/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/package.json)","tokens":300,"sizeBytes":202},{"name":"tsconfig.json","path":"packages/kubectl-versions/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/tsconfig.json","title":"Kubectl-versions Skill","category":"anthropic-skill","format":"json","content":"# Kubectl-versions Skill\n\nPath: `packages/kubectl-versions/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/tsconfig.json)","tokens":300,"sizeBytes":204},{"name":"package.json","path":"packages/list-layout/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/list-layout/package.json","title":"List-layout Skill","category":"anthropic-skill","format":"json","content":"# List-layout Skill\n\nPath: `packages/list-layout/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/list-layout/package.json)","tokens":300,"sizeBytes":187},{"name":"tsconfig.json","path":"packages/list-layout/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/list-layout/tsconfig.json","title":"List-layout Skill","category":"anthropic-skill","format":"json","content":"# List-layout Skill\n\nPath: `packages/list-layout/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/list-layout/tsconfig.json)","tokens":300,"sizeBytes":189},{"name":"package.json","path":"packages/logger/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/logger/package.json","title":"Logger Skill","category":"anthropic-skill","format":"json","content":"# Logger Skill\n\nPath: `packages/logger/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/logger/package.json)","tokens":300,"sizeBytes":172},{"name":"tsconfig.json","path":"packages/logger/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/logger/tsconfig.json","title":"Logger Skill","category":"anthropic-skill","format":"json","content":"# Logger Skill\n\nPath: `packages/logger/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/logger/tsconfig.json)","tokens":300,"sizeBytes":174},{"name":"package.json","path":"packages/metrics/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/metrics/package.json","title":"@freelensapp/metrics","category":"anthropic-skill","format":"json","content":"{\n  \"name\": \"@freelensapp/metrics\",\n  \"version\": \"2.0.0-0\",\n  \"private\": true,\n  \"description\": \"Injection tokens for implementing metrics for Freelens\",\n  \"homepage\": \"https://freelens.app\",\n  \"bugs\": {\n    \"url\": \"https://github.com/freelensapp/freelens/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/freelensapp/freelens.git\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"author\": {\n    \"name\": \"Freelens Authors\",\n    \"email\": \"freelens@freelens.app\"\n  },\n  \"main\": \"./index.ts\",\n  \"types\": \"./index.ts\",\n  \"scripts\": {\n    \"clean:dist\": \"pnpm dlx rimraf@6.1.3 dist\"\n  },\n  \"dependencies\": {\n    \"@ogre-tools/injectable\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@freelensapp/kube-object\": \"workspace:^\",\n    \"@freelensapp/typescript\": \"workspace:^\",\n    \"@types/react\": \"catalog:\",\n    \"react\": \"catalog:\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  }\n}\n","frontmatter":{"name":"@freelensapp/metrics","version":"2.0.0-0","private":true,"description":"Injection tokens for implementing metrics for Freelens","homepage":"https://freelens.app","bugs":{"url":"https://github.com/freelensapp/freelens/issues"},"repository":{"type":"git","url":"git+https://github.com/freelensapp/freelens.git"},"license":"MIT","type":"module","author":{"name":"Freelens Authors","email":"freelens@freelens.app"},"main":"./index.ts","types":"./index.ts","scripts":{"clean:dist":"pnpm dlx rimraf@6.1.3 dist"},"dependencies":{"@ogre-tools/injectable":"catalog:"},"devDependencies":{"@freelensapp/kube-object":"workspace:^","@freelensapp/typescript":"workspace:^","@types/react":"catalog:","react":"catalog:"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"}},"isInternal":false,"tokens":308,"sizeBytes":956},{"name":"tsconfig.json","path":"packages/metrics/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/metrics/tsconfig.json","title":"Metrics Skill","category":"anthropic-skill","format":"json","content":"# Metrics Skill\n\nPath: `packages/metrics/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/metrics/tsconfig.json)","tokens":300,"sizeBytes":177},{"name":"package.json","path":"packages/random/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/random/package.json","title":"@freelensapp/random","category":"anthropic-skill","format":"json","content":"{\n  \"name\": \"@freelensapp/random\",\n  \"version\": \"2.0.0-0\",\n  \"private\": true,\n  \"description\": \"Highly extendable random in the Freelens.\",\n  \"homepage\": \"https://freelens.app\",\n  \"bugs\": {\n    \"url\": \"https://github.com/freelensapp/freelens/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/freelensapp/freelens.git\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"author\": {\n    \"name\": \"Freelens Authors\",\n    \"email\": \"freelens@freelens.app\"\n  },\n  \"exports\": {\n    \".\": \"./index.ts\"\n  },\n  \"main\": \"./index.ts\",\n  \"types\": \"./index.ts\",\n  \"scripts\": {},\n  \"dependencies\": {\n    \"@freelensapp/feature-core\": \"workspace:^\",\n    \"@ogre-tools/injectable\": \"catalog:\",\n    \"uuid\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@freelensapp/typescript\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  }\n}\n","frontmatter":{"name":"@freelensapp/random","version":"2.0.0-0","private":true,"description":"Highly extendable random in the Freelens.","homepage":"https://freelens.app","bugs":{"url":"https://github.com/freelensapp/freelens/issues"},"repository":{"type":"git","url":"git+https://github.com/freelensapp/freelens.git"},"license":"MIT","type":"module","author":{"name":"Freelens Authors","email":"freelens@freelens.app"},"exports":{".":"./index.ts"},"main":"./index.ts","types":"./index.ts","scripts":{},"dependencies":{"@freelensapp/feature-core":"workspace:^","@ogre-tools/injectable":"catalog:","uuid":"catalog:"},"devDependencies":{"@freelensapp/typescript":"workspace:^"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"}},"isInternal":false,"tokens":291,"sizeBytes":902},{"name":"tsconfig.json","path":"packages/random/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/random/tsconfig.json","title":"Random Skill","category":"anthropic-skill","format":"json","content":"{\n  \"extends\": \"@freelensapp/typescript/config/base.json\",\n  \"include\": [\"**/*.ts\", \"**/*.tsx\"]\n}\n","frontmatter":{"extends":"@freelensapp/typescript/config/base.json","include":["**/*.ts","**/*.tsx"]},"isInternal":false,"tokens":30,"sizeBytes":98},{"name":"package.json","path":"packages/resource-templates/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/package.json","title":"@freelensapp/resource-templates","category":"anthropic-skill","format":"json","content":"{\n  \"name\": \"@freelensapp/resource-templates\",\n  \"version\": \"2.0.0-0\",\n  \"private\": true,\n  \"homepage\": \"https://freelens.app\",\n  \"bugs\": {\n    \"url\": \"https://github.com/freelensapp/freelens/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/freelensapp/freelens.git\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"author\": {\n    \"name\": \"Freelens Authors\",\n    \"email\": \"freelens@freelens.app\"\n  },\n  \"files\": [\n    \"templates/**/*\"\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"copyright\": \"© 2023 OpenLens Authors\"\n}\n","frontmatter":{"name":"@freelensapp/resource-templates","version":"2.0.0-0","private":true,"homepage":"https://freelens.app","bugs":{"url":"https://github.com/freelensapp/freelens/issues"},"repository":{"type":"git","url":"git+https://github.com/freelensapp/freelens.git"},"license":"MIT","type":"module","author":{"name":"Freelens Authors","email":"freelens@freelens.app"},"files":["templates/**/*"],"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"copyright":"© 2023 OpenLens Authors"},"isInternal":false,"tokens":208,"sizeBytes":615},{"name":".yamlfmt.yaml","path":"packages/resource-templates/templates/.yamlfmt.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/.yamlfmt.yaml","title":"Templates Skill","category":"anthropic-skill","format":"yaml","content":"# Templates Skill\n\nPath: `packages/resource-templates/templates/.yamlfmt.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/.yamlfmt.yaml)","tokens":300,"sizeBytes":221},{"name":"ClusterRole.yaml","path":"packages/resource-templates/templates/create-resource/ClusterRole.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ClusterRole.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/ClusterRole.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ClusterRole.yaml)","tokens":300,"sizeBytes":265},{"name":"ClusterRoleBinding.yaml","path":"packages/resource-templates/templates/create-resource/ClusterRoleBinding.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ClusterRoleBinding.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/ClusterRoleBinding.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ClusterRoleBinding.yaml)","tokens":300,"sizeBytes":279},{"name":"ConfigMap.yaml","path":"packages/resource-templates/templates/create-resource/ConfigMap.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ConfigMap.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/ConfigMap.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ConfigMap.yaml)","tokens":300,"sizeBytes":261},{"name":"CronJob.yaml","path":"packages/resource-templates/templates/create-resource/CronJob.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/CronJob.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/CronJob.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/CronJob.yaml)","tokens":300,"sizeBytes":257},{"name":"DaemonSet.yaml","path":"packages/resource-templates/templates/create-resource/DaemonSet.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/DaemonSet.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/DaemonSet.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/DaemonSet.yaml)","tokens":300,"sizeBytes":261},{"name":"Deployment.yaml","path":"packages/resource-templates/templates/create-resource/Deployment.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Deployment.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Deployment.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Deployment.yaml)","tokens":300,"sizeBytes":263},{"name":"Ingress.yaml","path":"packages/resource-templates/templates/create-resource/Ingress.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Ingress.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Ingress.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Ingress.yaml)","tokens":300,"sizeBytes":257},{"name":"Job.yaml","path":"packages/resource-templates/templates/create-resource/Job.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Job.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Job.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Job.yaml)","tokens":300,"sizeBytes":249},{"name":"Namespace.yaml","path":"packages/resource-templates/templates/create-resource/Namespace.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Namespace.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Namespace.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Namespace.yaml)","tokens":300,"sizeBytes":261},{"name":"NetworkPolicy.yaml","path":"packages/resource-templates/templates/create-resource/NetworkPolicy.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/NetworkPolicy.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/NetworkPolicy.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/NetworkPolicy.yaml)","tokens":300,"sizeBytes":269},{"name":"PersistentVolume.yaml","path":"packages/resource-templates/templates/create-resource/PersistentVolume.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/PersistentVolume.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/PersistentVolume.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/PersistentVolume.yaml)","tokens":300,"sizeBytes":275},{"name":"PersistentVolumeClaim.yaml","path":"packages/resource-templates/templates/create-resource/PersistentVolumeClaim.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/PersistentVolumeClaim.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/PersistentVolumeClaim.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/PersistentVolumeClaim.yaml)","tokens":300,"sizeBytes":285},{"name":"Pod.yaml","path":"packages/resource-templates/templates/create-resource/Pod.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Pod.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Pod.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Pod.yaml)","tokens":300,"sizeBytes":249},{"name":"PriorityClass.yaml","path":"packages/resource-templates/templates/create-resource/PriorityClass.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/PriorityClass.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/PriorityClass.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/PriorityClass.yaml)","tokens":300,"sizeBytes":269},{"name":"ReplicaSet.yaml","path":"packages/resource-templates/templates/create-resource/ReplicaSet.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ReplicaSet.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/ReplicaSet.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ReplicaSet.yaml)","tokens":300,"sizeBytes":263},{"name":"ReplicationController.yaml","path":"packages/resource-templates/templates/create-resource/ReplicationController.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ReplicationController.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/ReplicationController.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/ReplicationController.yaml)","tokens":300,"sizeBytes":285},{"name":"Role.yaml","path":"packages/resource-templates/templates/create-resource/Role.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Role.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Role.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Role.yaml)","tokens":300,"sizeBytes":251},{"name":"RoleBinding.yaml","path":"packages/resource-templates/templates/create-resource/RoleBinding.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/RoleBinding.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/RoleBinding.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/RoleBinding.yaml)","tokens":300,"sizeBytes":265},{"name":"RuntimeClass.yaml","path":"packages/resource-templates/templates/create-resource/RuntimeClass.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/RuntimeClass.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/RuntimeClass.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/RuntimeClass.yaml)","tokens":300,"sizeBytes":267},{"name":"Secret.yaml","path":"packages/resource-templates/templates/create-resource/Secret.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Secret.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Secret.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Secret.yaml)","tokens":300,"sizeBytes":255},{"name":"Service.yaml","path":"packages/resource-templates/templates/create-resource/Service.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Service.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/Service.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/Service.yaml)","tokens":300,"sizeBytes":257},{"name":"StatefulSet.yaml","path":"packages/resource-templates/templates/create-resource/StatefulSet.yaml","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/StatefulSet.yaml","title":"Create-resource Skill","category":"anthropic-skill","format":"yaml","content":"# Create-resource Skill\n\nPath: `packages/resource-templates/templates/create-resource/StatefulSet.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/resource-templates/templates/create-resource/StatefulSet.yaml)","tokens":300,"sizeBytes":265},{"name":"package.json","path":"packages/routing/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/routing/package.json","title":"@freelensapp/routing","category":"anthropic-skill","format":"json","content":"{\n  \"name\": \"@freelensapp/routing\",\n  \"version\": \"2.0.0-0\",\n  \"private\": true,\n  \"description\": \"Highly extendable routing in the Freelens.\",\n  \"homepage\": \"https://freelens.app\",\n  \"bugs\": {\n    \"url\": \"https://github.com/freelensapp/freelens/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/freelensapp/freelens.git\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"author\": {\n    \"name\": \"Freelens Authors\",\n    \"email\": \"freelens@freelens.app\"\n  },\n  \"main\": \"./index.ts\",\n  \"types\": \"./index.ts\",\n  \"scripts\": {},\n  \"dependencies\": {\n    \"@freelensapp/feature-core\": \"workspace:^\",\n    \"@ogre-tools/fp\": \"catalog:\",\n    \"@ogre-tools/injectable\": \"catalog:\",\n    \"@ogre-tools/injectable-react\": \"catalog:\",\n    \"mobx\": \"catalog:\",\n    \"mobx-react\": \"catalog:\",\n    \"react\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@freelensapp/typescript\": \"workspace:^\",\n    \"@ogre-tools/injectable-extension-for-mobx\": \"catalog:\",\n    \"@testing-library/jest-dom\": \"catalog:\",\n    \"@testing-library/react\": \"catalog:\",\n    \"@testing-library/user-event\": \"catalog:\",\n    \"@types/react\": \"catalog:\",\n    \"@types/react-dom\": \"catalog:\",\n    \"react-dom\": \"catalog:\",\n    \"vitest\": \"catalog:\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org/\"\n  }\n}\n","frontmatter":{"name":"@freelensapp/routing","version":"2.0.0-0","private":true,"description":"Highly extendable routing in the Freelens.","homepage":"https://freelens.app","bugs":{"url":"https://github.com/freelensapp/freelens/issues"},"repository":{"type":"git","url":"git+https://github.com/freelensapp/freelens.git"},"license":"MIT","type":"module","author":{"name":"Freelens Authors","email":"freelens@freelens.app"},"main":"./index.ts","types":"./index.ts","scripts":{},"dependencies":{"@freelensapp/feature-core":"workspace:^","@ogre-tools/fp":"catalog:","@ogre-tools/injectable":"catalog:","@ogre-tools/injectable-react":"catalog:","mobx":"catalog:","mobx-react":"catalog:","react":"catalog:"},"devDependencies":{"@freelensapp/typescript":"workspace:^","@ogre-tools/injectable-extension-for-mobx":"catalog:","@testing-library/jest-dom":"catalog:","@testing-library/react":"catalog:","@testing-library/user-event":"catalog:","@types/react":"catalog:","@types/react-dom":"catalog:","react-dom":"catalog:","vitest":"catalog:"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"}},"isInternal":false,"tokens":397,"sizeBytes":1317},{"name":"tsconfig.json","path":"packages/routing/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/routing/tsconfig.json","title":"Routing Skill","category":"anthropic-skill","format":"json","content":"{\n  \"extends\": \"@freelensapp/typescript/config/base.json\",\n  \"include\": [\"**/*.ts\", \"**/*.tsx\"]\n}\n","frontmatter":{"extends":"@freelensapp/typescript/config/base.json","include":["**/*.ts","**/*.tsx"]},"isInternal":false,"tokens":30,"sizeBytes":98},{"name":"package.json","path":"packages/semver/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/semver/package.json","title":"@freelensapp/semver","category":"anthropic-skill","format":"json","content":"{\n  \"name\": \"@freelensapp/semver\",\n  \"version\": \"2.0.0-0\",\n  \"private\": true,\n  \"description\": \"CLI over verkit package for picking parts of a version\",\n  \"homepage\": \"https://freelens.app\",\n  \"bugs\": {\n    \"url\": \"https://github.com/freelensapp/freelens/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/freelensapp/freelens.git\"\n  },\n  \"license\": \"MIT\",\n  \"author\": {\n    \"name\": \"Freelens Authors\",\n    \"email\": \"freelens@freelens.app\"\n  },\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"tsc --pretty --project .\",\n    \"build:dev\": \"tsc --pretty --project .\",\n    \"clean:dist\": \"pnpm dlx rimraf@6.1.3 dist\"\n  },\n  \"dependencies\": {\n    \"command-line-args\": \"catalog:\",\n    \"verkit\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@types/command-line-args\": \"catalog:\",\n    \"@types/node\": \"catalog:\",\n    \"typescript\": \"catalog:\"\n  }\n}\n","frontmatter":{"name":"@freelensapp/semver","version":"2.0.0-0","private":true,"description":"CLI over verkit package for picking parts of a version","homepage":"https://freelens.app","bugs":{"url":"https://github.com/freelensapp/freelens/issues"},"repository":{"type":"git","url":"git+https://github.com/freelensapp/freelens.git"},"license":"MIT","author":{"name":"Freelens Authors","email":"freelens@freelens.app"},"type":"module","scripts":{"build":"tsc --pretty --project .","build:dev":"tsc --pretty --project .","clean:dist":"pnpm dlx rimraf@6.1.3 dist"},"dependencies":{"command-line-args":"catalog:","verkit":"catalog:"},"devDependencies":{"@types/command-line-args":"catalog:","@types/node":"catalog:","typescript":"catalog:"}},"isInternal":false,"tokens":286,"sizeBytes":872},{"name":"tsconfig.json","path":"packages/semver/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/semver/tsconfig.json","title":"Semver Skill","category":"anthropic-skill","format":"json","content":"{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"dist/\",\n    \"rootDir\": \"src/\",\n    \"types\": [\"node\"]\n  },\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"node_modules\"]\n}\n","frontmatter":{"extends":"../../tsconfig.json","compilerOptions":{"outDir":"dist/","rootDir":"src/","types":["node"]},"include":["src/**/*"],"exclude":["node_modules"]},"isInternal":false,"tokens":59,"sizeBytes":193},{"name":"package.json","path":"packages/technical-features/application/application-for-electron-main/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application-for-electron-main/package.json","title":"Application-for-electron-main Skill","category":"anthropic-skill","format":"json","content":"# Application-for-electron-main Skill\n\nPath: `packages/technical-features/application/application-for-electron-main/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application-for-electron-main/package.json)","tokens":300,"sizeBytes":303},{"name":"tsconfig.json","path":"packages/technical-features/application/application-for-electron-main/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application-for-electron-main/tsconfig.json","title":"Application-for-electron-main Skill","category":"anthropic-skill","format":"json","content":"# Application-for-electron-main Skill\n\nPath: `packages/technical-features/application/application-for-electron-main/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application-for-electron-main/tsconfig.json)","tokens":300,"sizeBytes":305},{"name":"package.json","path":"packages/technical-features/application/application/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application/package.json","title":"Application Skill","category":"anthropic-skill","format":"json","content":"# Application Skill\n\nPath: `packages/technical-features/application/application/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application/package.json)","tokens":300,"sizeBytes":249},{"name":"tsconfig.json","path":"packages/technical-features/application/application/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application/tsconfig.json","title":"Application Skill","category":"anthropic-skill","format":"json","content":"# Application Skill\n\nPath: `packages/technical-features/application/application/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application/tsconfig.json)","tokens":300,"sizeBytes":251},{"name":"package.json","path":"packages/technical-features/feature-core/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/feature-core/package.json","title":"Feature-core Skill","category":"anthropic-skill","format":"json","content":"# Feature-core Skill\n\nPath: `packages/technical-features/feature-core/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/feature-core/package.json)","tokens":300,"sizeBytes":228},{"name":"tsconfig.json","path":"packages/technical-features/feature-core/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/feature-core/tsconfig.json","title":"Feature-core Skill","category":"anthropic-skill","format":"json","content":"# Feature-core Skill\n\nPath: `packages/technical-features/feature-core/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/feature-core/tsconfig.json)","tokens":300,"sizeBytes":230},{"name":"package.json","path":"packages/technical-features/messaging/computed-channel/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/computed-channel/package.json","title":"Computed-channel Skill","category":"anthropic-skill","format":"json","content":"# Computed-channel Skill\n\nPath: `packages/technical-features/messaging/computed-channel/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/computed-channel/package.json)","tokens":300,"sizeBytes":260},{"name":"tsconfig.json","path":"packages/technical-features/messaging/computed-channel/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/computed-channel/tsconfig.json","title":"Computed-channel Skill","category":"anthropic-skill","format":"json","content":"# Computed-channel Skill\n\nPath: `packages/technical-features/messaging/computed-channel/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/computed-channel/tsconfig.json)","tokens":300,"sizeBytes":262},{"name":"package.json","path":"packages/technical-features/messaging/messaging-fake-bridge/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-fake-bridge/package.json","title":"Messaging-fake-bridge Skill","category":"anthropic-skill","format":"json","content":"# Messaging-fake-bridge Skill\n\nPath: `packages/technical-features/messaging/messaging-fake-bridge/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-fake-bridge/package.json)","tokens":300,"sizeBytes":275},{"name":"tsconfig.json","path":"packages/technical-features/messaging/messaging-fake-bridge/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-fake-bridge/tsconfig.json","title":"Messaging-fake-bridge Skill","category":"anthropic-skill","format":"json","content":"# Messaging-fake-bridge Skill\n\nPath: `packages/technical-features/messaging/messaging-fake-bridge/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-fake-bridge/tsconfig.json)","tokens":300,"sizeBytes":277},{"name":"package.json","path":"packages/technical-features/messaging/messaging-for-main/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-for-main/package.json","title":"Messaging-for-main Skill","category":"anthropic-skill","format":"json","content":"# Messaging-for-main Skill\n\nPath: `packages/technical-features/messaging/messaging-for-main/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-for-main/package.json)","tokens":300,"sizeBytes":266},{"name":"tsconfig.json","path":"packages/technical-features/messaging/messaging-for-main/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-for-main/tsconfig.json","title":"Messaging-for-main Skill","category":"anthropic-skill","format":"json","content":"# Messaging-for-main Skill\n\nPath: `packages/technical-features/messaging/messaging-for-main/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-for-main/tsconfig.json)","tokens":300,"sizeBytes":268},{"name":"package.json","path":"packages/technical-features/messaging/messaging-for-renderer/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-for-renderer/package.json","title":"Messaging-for-renderer Skill","category":"anthropic-skill","format":"json","content":"# Messaging-for-renderer Skill\n\nPath: `packages/technical-features/messaging/messaging-for-renderer/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-for-renderer/package.json)","tokens":300,"sizeBytes":278},{"name":"tsconfig.json","path":"packages/technical-features/messaging/messaging-for-renderer/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-for-renderer/tsconfig.json","title":"Messaging-for-renderer Skill","category":"anthropic-skill","format":"json","content":"# Messaging-for-renderer Skill\n\nPath: `packages/technical-features/messaging/messaging-for-renderer/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging-for-renderer/tsconfig.json)","tokens":300,"sizeBytes":280},{"name":"package.json","path":"packages/technical-features/messaging/messaging/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging/package.json","title":"Messaging Skill","category":"anthropic-skill","format":"json","content":"# Messaging Skill\n\nPath: `packages/technical-features/messaging/messaging/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging/package.json)","tokens":300,"sizeBytes":239},{"name":"tsconfig.json","path":"packages/technical-features/messaging/messaging/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging/tsconfig.json","title":"Messaging Skill","category":"anthropic-skill","format":"json","content":"# Messaging Skill\n\nPath: `packages/technical-features/messaging/messaging/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/messaging/messaging/tsconfig.json)","tokens":300,"sizeBytes":241},{"name":"package.json","path":"packages/technical-features/prometheus/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/prometheus/package.json","title":"Prometheus Skill","category":"anthropic-skill","format":"json","content":"# Prometheus Skill\n\nPath: `packages/technical-features/prometheus/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/prometheus/package.json)","tokens":300,"sizeBytes":222},{"name":"tsconfig.json","path":"packages/technical-features/prometheus/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/prometheus/tsconfig.json","title":"Prometheus Skill","category":"anthropic-skill","format":"json","content":"# Prometheus Skill\n\nPath: `packages/technical-features/prometheus/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/prometheus/tsconfig.json)","tokens":300,"sizeBytes":224},{"name":"package.json","path":"packages/technical-features/react-application/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/react-application/package.json","title":"React-application Skill","category":"anthropic-skill","format":"json","content":"# React-application Skill\n\nPath: `packages/technical-features/react-application/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/react-application/package.json)","tokens":300,"sizeBytes":243},{"name":"tsconfig.json","path":"packages/technical-features/react-application/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/react-application/tsconfig.json","title":"React-application Skill","category":"anthropic-skill","format":"json","content":"# React-application Skill\n\nPath: `packages/technical-features/react-application/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/react-application/tsconfig.json)","tokens":300,"sizeBytes":245},{"name":"package.json","path":"packages/ui-components/animate/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/animate/package.json","title":"Animate Skill","category":"anthropic-skill","format":"json","content":"# Animate Skill\n\nPath: `packages/ui-components/animate/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/animate/package.json)","tokens":300,"sizeBytes":203},{"name":"tsconfig.json","path":"packages/ui-components/animate/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/animate/tsconfig.json","title":"Animate Skill","category":"anthropic-skill","format":"json","content":"# Animate Skill\n\nPath: `packages/ui-components/animate/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/animate/tsconfig.json)","tokens":300,"sizeBytes":205},{"name":"package.json","path":"packages/ui-components/button/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/button/package.json","title":"Button Skill","category":"anthropic-skill","format":"json","content":"# Button Skill\n\nPath: `packages/ui-components/button/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/button/package.json)","tokens":300,"sizeBytes":200},{"name":"tsconfig.json","path":"packages/ui-components/button/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/button/tsconfig.json","title":"Button Skill","category":"anthropic-skill","format":"json","content":"# Button Skill\n\nPath: `packages/ui-components/button/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/button/tsconfig.json)","tokens":300,"sizeBytes":202},{"name":"package.json","path":"packages/ui-components/error-boundary/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/error-boundary/package.json","title":"Error-boundary Skill","category":"anthropic-skill","format":"json","content":"# Error-boundary Skill\n\nPath: `packages/ui-components/error-boundary/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/error-boundary/package.json)","tokens":300,"sizeBytes":224},{"name":"tsconfig.json","path":"packages/ui-components/error-boundary/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/error-boundary/tsconfig.json","title":"Error-boundary Skill","category":"anthropic-skill","format":"json","content":"# Error-boundary Skill\n\nPath: `packages/ui-components/error-boundary/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/error-boundary/tsconfig.json)","tokens":300,"sizeBytes":226},{"name":"package.json","path":"packages/ui-components/icon/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/icon/package.json","title":"Icon Skill","category":"anthropic-skill","format":"json","content":"# Icon Skill\n\nPath: `packages/ui-components/icon/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/icon/package.json)","tokens":300,"sizeBytes":194},{"name":"tsconfig.json","path":"packages/ui-components/icon/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/icon/tsconfig.json","title":"Icon Skill","category":"anthropic-skill","format":"json","content":"# Icon Skill\n\nPath: `packages/ui-components/icon/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/icon/tsconfig.json)","tokens":300,"sizeBytes":196},{"name":"package.json","path":"packages/ui-components/notifications/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/notifications/package.json","title":"Notifications Skill","category":"anthropic-skill","format":"json","content":"# Notifications Skill\n\nPath: `packages/ui-components/notifications/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/notifications/package.json)","tokens":300,"sizeBytes":221},{"name":"tsconfig.json","path":"packages/ui-components/notifications/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/notifications/tsconfig.json","title":"Notifications Skill","category":"anthropic-skill","format":"json","content":"# Notifications Skill\n\nPath: `packages/ui-components/notifications/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/notifications/tsconfig.json)","tokens":300,"sizeBytes":223},{"name":"package.json","path":"packages/ui-components/resizing-anchor/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/resizing-anchor/package.json","title":"Resizing-anchor Skill","category":"anthropic-skill","format":"json","content":"# Resizing-anchor Skill\n\nPath: `packages/ui-components/resizing-anchor/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/resizing-anchor/package.json)","tokens":300,"sizeBytes":227},{"name":"tsconfig.json","path":"packages/ui-components/resizing-anchor/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/resizing-anchor/tsconfig.json","title":"Resizing-anchor Skill","category":"anthropic-skill","format":"json","content":"# Resizing-anchor Skill\n\nPath: `packages/ui-components/resizing-anchor/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/resizing-anchor/tsconfig.json)","tokens":300,"sizeBytes":229},{"name":"package.json","path":"packages/ui-components/spinner/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/spinner/package.json","title":"Spinner Skill","category":"anthropic-skill","format":"json","content":"# Spinner Skill\n\nPath: `packages/ui-components/spinner/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/spinner/package.json)","tokens":300,"sizeBytes":203},{"name":"tsconfig.json","path":"packages/ui-components/spinner/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/spinner/tsconfig.json","title":"Spinner Skill","category":"anthropic-skill","format":"json","content":"# Spinner Skill\n\nPath: `packages/ui-components/spinner/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/spinner/tsconfig.json)","tokens":300,"sizeBytes":205},{"name":"package.json","path":"packages/ui-components/tooltip/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/tooltip/package.json","title":"Tooltip Skill","category":"anthropic-skill","format":"json","content":"# Tooltip Skill\n\nPath: `packages/ui-components/tooltip/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/tooltip/package.json)","tokens":300,"sizeBytes":203},{"name":"tsconfig.json","path":"packages/ui-components/tooltip/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/tooltip/tsconfig.json","title":"Tooltip Skill","category":"anthropic-skill","format":"json","content":"# Tooltip Skill\n\nPath: `packages/ui-components/tooltip/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/tooltip/tsconfig.json)","tokens":300,"sizeBytes":205},{"name":"package.json","path":"packages/utility-features/event-emitter/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/event-emitter/package.json","title":"Event-emitter Skill","category":"anthropic-skill","format":"json","content":"# Event-emitter Skill\n\nPath: `packages/utility-features/event-emitter/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/event-emitter/package.json)","tokens":300,"sizeBytes":227},{"name":"tsconfig.json","path":"packages/utility-features/event-emitter/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/event-emitter/tsconfig.json","title":"Event-emitter Skill","category":"anthropic-skill","format":"json","content":"# Event-emitter Skill\n\nPath: `packages/utility-features/event-emitter/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/event-emitter/tsconfig.json)","tokens":300,"sizeBytes":229},{"name":"package.json","path":"packages/utility-features/json-api/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/json-api/package.json","title":"Json-api Skill","category":"anthropic-skill","format":"json","content":"# Json-api Skill\n\nPath: `packages/utility-features/json-api/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/json-api/package.json)","tokens":300,"sizeBytes":212},{"name":"tsconfig.json","path":"packages/utility-features/json-api/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/json-api/tsconfig.json","title":"Json-api Skill","category":"anthropic-skill","format":"json","content":"# Json-api Skill\n\nPath: `packages/utility-features/json-api/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/json-api/tsconfig.json)","tokens":300,"sizeBytes":214},{"name":"package.json","path":"packages/utility-features/kube-api-specifics/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/kube-api-specifics/package.json","title":"Kube-api-specifics Skill","category":"anthropic-skill","format":"json","content":"# Kube-api-specifics Skill\n\nPath: `packages/utility-features/kube-api-specifics/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/kube-api-specifics/package.json)","tokens":300,"sizeBytes":242},{"name":"tsconfig.json","path":"packages/utility-features/kube-api-specifics/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/kube-api-specifics/tsconfig.json","title":"Kube-api-specifics Skill","category":"anthropic-skill","format":"json","content":"# Kube-api-specifics Skill\n\nPath: `packages/utility-features/kube-api-specifics/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/kube-api-specifics/tsconfig.json)","tokens":300,"sizeBytes":244},{"name":"package.json","path":"packages/utility-features/kube-api/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/kube-api/package.json","title":"Kube-api Skill","category":"anthropic-skill","format":"json","content":"# Kube-api Skill\n\nPath: `packages/utility-features/kube-api/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/kube-api/package.json)","tokens":300,"sizeBytes":212},{"name":"tsconfig.json","path":"packages/utility-features/kube-api/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/kube-api/tsconfig.json","title":"Kube-api Skill","category":"anthropic-skill","format":"json","content":"# Kube-api Skill\n\nPath: `packages/utility-features/kube-api/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/kube-api/tsconfig.json)","tokens":300,"sizeBytes":214},{"name":"package.json","path":"packages/utility-features/react-testing-library-discovery/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/react-testing-library-discovery/package.json","title":"React-testing-library-discovery Skill","category":"anthropic-skill","format":"json","content":"# React-testing-library-discovery Skill\n\nPath: `packages/utility-features/react-testing-library-discovery/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/react-testing-library-discovery/package.json)","tokens":300,"sizeBytes":281},{"name":"tsconfig.json","path":"packages/utility-features/react-testing-library-discovery/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/react-testing-library-discovery/tsconfig.json","title":"React-testing-library-discovery Skill","category":"anthropic-skill","format":"json","content":"# React-testing-library-discovery Skill\n\nPath: `packages/utility-features/react-testing-library-discovery/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/react-testing-library-discovery/tsconfig.json)","tokens":300,"sizeBytes":283},{"name":"package.json","path":"packages/utility-features/run-many/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/run-many/package.json","title":"Run-many Skill","category":"anthropic-skill","format":"json","content":"# Run-many Skill\n\nPath: `packages/utility-features/run-many/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/run-many/package.json)","tokens":300,"sizeBytes":212},{"name":"tsconfig.json","path":"packages/utility-features/run-many/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/run-many/tsconfig.json","title":"Run-many Skill","category":"anthropic-skill","format":"json","content":"# Run-many Skill\n\nPath: `packages/utility-features/run-many/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/run-many/tsconfig.json)","tokens":300,"sizeBytes":214},{"name":"package.json","path":"packages/utility-features/startable-stoppable/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/startable-stoppable/package.json","title":"Startable-stoppable Skill","category":"anthropic-skill","format":"json","content":"# Startable-stoppable Skill\n\nPath: `packages/utility-features/startable-stoppable/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/startable-stoppable/package.json)","tokens":300,"sizeBytes":245},{"name":"tsconfig.json","path":"packages/utility-features/startable-stoppable/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/startable-stoppable/tsconfig.json","title":"Startable-stoppable Skill","category":"anthropic-skill","format":"json","content":"# Startable-stoppable Skill\n\nPath: `packages/utility-features/startable-stoppable/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/startable-stoppable/tsconfig.json)","tokens":300,"sizeBytes":247},{"name":"package.json","path":"packages/utility-features/test-utils/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/test-utils/package.json","title":"Test-utils Skill","category":"anthropic-skill","format":"json","content":"# Test-utils Skill\n\nPath: `packages/utility-features/test-utils/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/test-utils/package.json)","tokens":300,"sizeBytes":218},{"name":"tsconfig.json","path":"packages/utility-features/test-utils/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/test-utils/tsconfig.json","title":"Test-utils Skill","category":"anthropic-skill","format":"json","content":"# Test-utils Skill\n\nPath: `packages/utility-features/test-utils/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/test-utils/tsconfig.json)","tokens":300,"sizeBytes":220},{"name":"package.json","path":"packages/utility-features/utilities/package.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/utilities/package.json","title":"Utilities Skill","category":"anthropic-skill","format":"json","content":"# Utilities Skill\n\nPath: `packages/utility-features/utilities/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/utilities/package.json)","tokens":300,"sizeBytes":215},{"name":"tsconfig.json","path":"packages/utility-features/utilities/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/utilities/tsconfig.json","title":"Utilities Skill","category":"anthropic-skill","format":"json","content":"# Utilities Skill\n\nPath: `packages/utility-features/utilities/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/utilities/tsconfig.json)","tokens":300,"sizeBytes":217},{"name":"CLAUDE.md","path":"CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/CLAUDE.md","title":"Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"@AGENTS.md\n\n# Agent Guide\n\nThis project uses AGENTS.md as the canonical agent guide (imported above).\nClaude Code reads it via @AGENTS.md, while other agents read it directly.\n","isInternal":false,"tokens":43,"sizeBytes":176},{"name":"README.md","path":"packages/business-features/keyboard-shortcuts/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/business-features/keyboard-shortcuts/README.md","title":"keyboard-shortcuts Documentation","category":"plugin-manifest","format":"markdown","content":"# keyboard-shortcuts Documentation\n\nPath: `packages/business-features/keyboard-shortcuts/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/business-features/keyboard-shortcuts/README.md)","tokens":300,"sizeBytes":246},{"name":"README.md","path":"packages/cluster-settings/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-settings/README.md","title":"cluster-settings Documentation","category":"plugin-manifest","format":"markdown","content":"# cluster-settings Documentation\n\nPath: `packages/cluster-settings/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-settings/README.md)","tokens":300,"sizeBytes":204},{"name":"README.md","path":"packages/infrastructure/typescript/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/infrastructure/typescript/README.md","title":"typescript Documentation","category":"plugin-manifest","format":"markdown","content":"# typescript Documentation\n\nPath: `packages/infrastructure/typescript/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/infrastructure/typescript/README.md)","tokens":300,"sizeBytes":216},{"name":"README.md","path":"packages/kubectl-versions/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/README.md","title":"kubectl-versions Documentation","category":"plugin-manifest","format":"markdown","content":"# kubectl-versions Documentation\n\nPath: `packages/kubectl-versions/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/README.md)","tokens":300,"sizeBytes":204},{"name":"README.md","path":"packages/logger/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/logger/README.md","title":"logger Documentation","category":"plugin-manifest","format":"markdown","content":"# logger Documentation\n\nPath: `packages/logger/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/logger/README.md)","tokens":300,"sizeBytes":174},{"name":"README.md","path":"packages/random/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/random/README.md","title":"random Documentation","category":"plugin-manifest","format":"markdown","content":"# @freelensapp/random\n\nThis package contains stuff related to creating Lens-applications. \n\n## Usage\n\n```sh\nnpm install @freelensapp/random\n```\n\n```typescript\nexport type { ... } from \"@freelensapp/random\";\n```\n\n## Extendability\n","isInternal":false,"tokens":59,"sizeBytes":229},{"name":"README.md","path":"packages/routing/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/routing/README.md","title":"routing Documentation","category":"plugin-manifest","format":"markdown","content":"# @freelensapp/routing\n\nThis package contains stuff related to creating Lens-applications. \n\n## Usage\n\n```sh\nnpm install @freelensapp/routing\n```\n\n```typescript\nimport { observableHistoryInjectable } from \"@freelensapp/routing\";\nimport { searchParamsOptions } from \"@freelensapp/routing\";\n```\n\n## Extendability\n","isInternal":false,"tokens":79,"sizeBytes":311},{"name":"README.md","path":"packages/technical-features/application/application-for-electron-main/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application-for-electron-main/README.md","title":"application-for-electron-main Documentation","category":"plugin-manifest","format":"markdown","content":"# application-for-electron-main Documentation\n\nPath: `packages/technical-features/application/application-for-electron-main/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application-for-electron-main/README.md)","tokens":300,"sizeBytes":305},{"name":"README.md","path":"packages/technical-features/application/application/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application/README.md","title":"application Documentation","category":"plugin-manifest","format":"markdown","content":"# application Documentation\n\nPath: `packages/technical-features/application/application/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/application/application/README.md)","tokens":300,"sizeBytes":251},{"name":"README.md","path":"packages/technical-features/feature-core/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/feature-core/README.md","title":"feature-core Documentation","category":"plugin-manifest","format":"markdown","content":"# feature-core Documentation\n\nPath: `packages/technical-features/feature-core/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/feature-core/README.md)","tokens":300,"sizeBytes":230},{"name":"README.md","path":"packages/technical-features/react-application/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/react-application/README.md","title":"react-application Documentation","category":"plugin-manifest","format":"markdown","content":"# react-application Documentation\n\nPath: `packages/technical-features/react-application/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/technical-features/react-application/README.md)","tokens":300,"sizeBytes":245},{"name":"README.md","path":"packages/ui-components/animate/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/animate/README.md","title":"animate Documentation","category":"plugin-manifest","format":"markdown","content":"# animate Documentation\n\nPath: `packages/ui-components/animate/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/animate/README.md)","tokens":300,"sizeBytes":205},{"name":"README.md","path":"packages/ui-components/button/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/button/README.md","title":"button Documentation","category":"plugin-manifest","format":"markdown","content":"# button Documentation\n\nPath: `packages/ui-components/button/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/button/README.md)","tokens":300,"sizeBytes":202},{"name":"README.md","path":"packages/ui-components/error-boundary/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/error-boundary/README.md","title":"error-boundary Documentation","category":"plugin-manifest","format":"markdown","content":"# error-boundary Documentation\n\nPath: `packages/ui-components/error-boundary/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/error-boundary/README.md)","tokens":300,"sizeBytes":226},{"name":"README.md","path":"packages/ui-components/icon/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/icon/README.md","title":"icon Documentation","category":"plugin-manifest","format":"markdown","content":"# icon Documentation\n\nPath: `packages/ui-components/icon/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/icon/README.md)","tokens":300,"sizeBytes":196},{"name":"README.md","path":"packages/ui-components/notifications/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/notifications/README.md","title":"notifications Documentation","category":"plugin-manifest","format":"markdown","content":"# notifications Documentation\n\nPath: `packages/ui-components/notifications/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/notifications/README.md)","tokens":300,"sizeBytes":223},{"name":"README.md","path":"packages/ui-components/resizing-anchor/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/resizing-anchor/README.md","title":"resizing-anchor Documentation","category":"plugin-manifest","format":"markdown","content":"# resizing-anchor Documentation\n\nPath: `packages/ui-components/resizing-anchor/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/resizing-anchor/README.md)","tokens":300,"sizeBytes":229},{"name":"README.md","path":"packages/ui-components/spinner/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/spinner/README.md","title":"spinner Documentation","category":"plugin-manifest","format":"markdown","content":"# spinner Documentation\n\nPath: `packages/ui-components/spinner/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/spinner/README.md)","tokens":300,"sizeBytes":205},{"name":"README.md","path":"packages/ui-components/tooltip/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/tooltip/README.md","title":"tooltip Documentation","category":"plugin-manifest","format":"markdown","content":"# tooltip Documentation\n\nPath: `packages/ui-components/tooltip/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ui-components/tooltip/README.md)","tokens":300,"sizeBytes":205},{"name":"README.md","path":"packages/utility-features/run-many/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/run-many/README.md","title":"run-many Documentation","category":"plugin-manifest","format":"markdown","content":"# run-many Documentation\n\nPath: `packages/utility-features/run-many/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/run-many/README.md)","tokens":300,"sizeBytes":214},{"name":"README.md","path":"packages/utility-features/test-utils/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/test-utils/README.md","title":"test-utils Documentation","category":"plugin-manifest","format":"markdown","content":"# test-utils Documentation\n\nPath: `packages/utility-features/test-utils/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/test-utils/README.md)","tokens":300,"sizeBytes":220},{"name":"README.md","path":"packages/utility-features/utilities/README.md","rawUrl":"https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/utilities/README.md","title":"utilities Documentation","category":"plugin-manifest","format":"markdown","content":"# utilities Documentation\n\nPath: `packages/utility-features/utilities/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/utility-features/utilities/README.md)","tokens":300,"sizeBytes":217}],"systemPromptSnippet":"<yakaai_skills repo=\"freelensapp/freelens\">\n<!-- File: AGENTS.md (Tokens: ~12041 | Category: root-instruction) -->\n# Agent Guide: Freelens Development\n\n## Overview\n\nThis guide helps AI agents understand the Freelens codebase, common development tasks, troubleshooting patterns, and key architectural decisions. Use this as a reference when working on the project.\n\nFor local development environment setup and extra development tips, see DEVELOPMENT.md.\n\n- **`freelens/`** - Main Electron application\n  - `src/main/` - Main Electron process code\n  - `src/renderer/` - Renderer process (UI) code\n  - `src/common/` - Shared code between processes\n- **`packages/core/`** - Core functionality\n  - `src/features/` - Feature modules organized by domain\n  - `src/renderer/` - Renderer-specific utilities\n  - `src/extensions/` - Extension system\n- **`packages/`** - Monorepo packages (utilities, components, etc.)\n- **`scripts/`** - Build and development scripts\n\n## Security\n\nNever read, display, reference, or include the contents of the following files in any response or context, even if they are open in the editor:\n\n- `.env`\n- `.env.*`\n- `.envrc`\n- `.npmrc`\n- `*.jks`\n- `*.keystore`\n- `*.p12`\n- `*.pfx`\n- `*.pem`\n- `*.key`\n\nThe same list is git-ignored in `.gitignore` and enforced for Claude Code by\nthe `permissions.deny` rules in `.claude/settings.json`, which block reading\nand editing these files. Change all three together. The rules are native\npermissions rather than a hook on purpose: a hook runs a process in the\nworking tree, which may be an untrusted pull request, and an interpreter such\nas `python3 -c` imports modules from that tree before the hook's own code.\n\n## Session and temporary files\n\nFiles created while working on a task — scratch scripts, command output,\nscreenshots, DOM/accessibility snapshots, and AI-agent / MCP-server runtime\nartifacts — must never be written into the tracked working tree, or they leak\ninto git history. Write them to a system temporary directory outside the repo\n(e.g. under `$TMPDIR`, or `mktemp -d`), not to the repo root.\n\nWhen a tool insists on writing inside the repo, keep it out of git:\n\n- point it at a temp path if it accepts one (e.g. pass an absolute\n  `$TMPDIR/...` filename), otherwise\n- git-ignore its default output directory. Already ignored:\n  `.playwright-mcp/` (Playwright MCP), `logs/` (electron-mcp-server).\n\nNever `git add -A` / `git add .` blindly: review `git status` first and stage\nonly the files your change actually touches, never these artifacts.\n\n### Running a scratch script with the project's toolchain\n\nmise picks the pinned Node from the `mise.toml` of the current directory, so a\nscript outside the repository runs on whatever Node is global unless mise is\npointed at the repository. `mise -C <repo>` (`--cd`) does that by changing the\nworking directory before it runs the command, which also moves where relative\npaths resolve: `mise -C <repo> exec -- node spike.mjs`, run from the script's\ndirectory, looks for `<repo>/spike.mjs` and fails with `Cannot find module`.\nRun from the repository and pass the script by its absolute path instead:\n\n```sh\ncd <repo> && mise exec -- node \"$TMPDIR/spike/spike.mjs\"\n```\n\nThe same applies to every relative argument of the command, input and output\nfiles included.\n\nA script outside the tree does not resolve the project's dependencies either:\nNode looks for `node_modules` next to the script, not in the working\ndirectory. Resolve them from the package that declares them, so the script\ngets the versions the application uses:\n\n```js\nimport { createRequire } from \"node:module\";\n\nconst require = createRequire(\"<repo>/packages/core/package.json\");\nconst { Agent, fetch } = require(\"undici\");\n```\n\nSource files carry one of two header variants. Which one a file gets depends\non whether it continues code from the original OpenLens fork, not on what its\nneighbours in the same directory look like.\n\n**New files** — anything created from scratch, including rewrites,\ntranslations, and reimplementations of removed or legacy logic — get the\nsingle-line variant:\n\n```ts\n/**\n * Copyright (c) Freelens Authors. All rights reserved.\n * Licensed under MIT License. See LICENSE in root directory for more information.\n */\n```\n\nThis holds even when the new file's logic is inspired by, or replaces, old\nOpenLens code: inspiration is not continuation. `freelens/electron.vite.config.ts`,\nwritten as a translation of the removed webpack config, is a new file.\n\n**Files that continue code from the fork** keep the two-line variant:\n\n```ts\n/**\n * Copyright (c) Freelens Authors. All rights reserved.\n * Copyright (c) OpenLens Authors. All rights reserved.\n * Licensed under MIT License. See LICENSE in root directory for more information.\n */\n```\n\nA file continues fork code when its path was present in the fork-import commit\n`0a5798c9` (\"First commit - Open Lens fork from master branch\"):\n\n```sh\ngit ls-tree -r --name-only 0a5798c9 | grep -x <path>\n```\n\nor when `git log --follow -- <path>` traces it back to a path that was — that\nis, git itself detects the file as a rename, move, or copy of fork-era code:\n\n```sh\ngit log --follow --format= --name-only -- <path> | sort -u\n```\n\nNever add the `OpenLens Authors` line to a file that does not already have it\njust because neighbouring files do. Do not touch legal or license text\n(`LICENSE`, `README.md`, `freelens/license-header.txt`,\n`freelens/static/build/license.txt`) or the upstream copyright notices of\nvendored third-party code, which are unrelated to either header variant.\n\nSee [#2352](https://github.com/freelensapp/freelens/issues/2352) for the\ncleanup that established this rule.\n\n## Comments in JSON\n\nComments belong in `.jsonc`, never in `.json` — regardless of what the consuming\nparser tolerates. TypeScript accepts `//` inside a `tsconfig.json`, and so do\nseveral other tools, but anything that reads the file as strict JSON because of\nits extension (`JSON.parse`, `jq`, an editor, a CI script) fails on it. No\n`.json` file in this repository has comments, `tsconfig*.json` included;\n`knip.jsonc` is where a commented configuration lives, and that is the right\npattern.\n\nWhen a `.json` file needs an explanation — why an entry is excluded, why a\nversion is pinned — put it somewhere it survives: the package README, this\nfile, or the pull request that introduced it. Do not smuggle it into the JSON.\n\n## Volatile Facts in Documentation\n\nDocumentation — `docs/`, the READMEs, this file — describes how things are,\nand has to stay true without anyone maintaining it. Keep out of it whatever\ngoes stale on its own:\n\n- issue and pull-request numbers,\n- dates,\n- counts that change without the document changing: how many extensions use\n  something, how many members a namespace has, how many files import a module,\n- the record of how it got there: which decisions were taken, which\n  alternatives were tried and rejected, what was deferred and why, what an\n  earlier version said, and status lines such as \"shipped\" or \"open\".\n\nState the rule or the fact rather than the measurement or the history that led\nto it: \"no extension is known to use it\", not \"none of the 29 surveyed\nextensions uses it\"; \"renderer code gets no guarantee of Node\", not \"decided in\nthe API review\". The measurement, the history and the issue references belong\nin the pull request description and the issue, which are dated by nature.\nThose are working notes; documentation is for the reader who uses the thing\nnow, and needs only its current state.\n\nExisting documents still carry such references. Do not copy them as a pattern,\nand drop them from a passage you are rewriting anyway.\n\n## Build System\n\n### Commands\n\n```bash\npnpm build:di           # Generate DI registration files\npnpm build              # Build all packages\npnpm build:app:dir      # Build Electron app directory\npnpm start              # Start development app\npnpm test               # Run tests\n```\n\n### Clean Build\n\nThis project uses Turbo for caching build artifacts.\n\nWhen facing caching issues:\n\n```bash\nrm -rf .turbo packages/core/dist freelens/dist\npnpm build\n```\n\n## Runtime Environments in Type-Checking\n\nThe application runs code in two environments: **main** (Node, Electron) and\n**renderer** (a browser page). `pnpm type:check` checks the sources of\n`freelens/src` and `packages/core/src` once per environment, so that an API the\nenvironment does not have fails the check before it fails at runtime:\n\n| Program                   | Environment                     | Checks                                  |\n| ------------------------- | ------------------------------- | --------------------------------------- |\n| `tsconfig.typecheck.json` | DOM and Node                    | every file, tests and unclassified ones |\n| `tsconfig.main.json`      | Node, no DOM                    | main and common files                   |\n| `tsconfig.renderer.json`  | DOM, no Node                    | renderer and common files               |\n\nThe two environment programs extend `tsconfig.typecheck.json`, so they share\nits `paths`. `pnpm type:check:environments` runs them alone.\n\n### Which environment a file belongs to\n\nThe context segments in a file's path decide:\n\n- `main/` or `main-api/` anywhere in the path: the main program;\n- `renderer/` or `renderer-api/` anywhere in the path: the renderer program;\n- `common/` or `common-api/` with neither of the above: both programs. A main\n  or renderer segment wins over common, so `renderer/common/` is renderer code.\n\nContexts nest anywhere (`features/*/{main,renderer,common}`), and the\n`include` and `exclude` globs of the two configs express exactly this rule.\nPut new code under a context directory. A file whose path carries no context\nhas to be listed in the `include` of the config (or both configs, for common\ncode) of the process that loads it; the lists at the end of both `include`\narrays hold the existing ones. An unlisted one is checked by the combined\nprogram only, like `extensions/extension-api.ts`, which bundles the types of\nall three extension API namespaces on purpose.\n\nTests and test support (`*.test.ts(x)`, `__tests__/`, `test-utils/`,\n`*.global-override-for-injectable.ts`, `getDiForUnitTesting`, …) are kept out\nof both programs, because Vitest runs them with DOM and Node alike.\n\nNo tsconfig declares the Vitest globals. TypeScript has no per-file globals,\nand tests share a program with the sources next to them, so declaring\n`describe` or `vi` for the tests would declare them for production code too.\nTest code imports what it uses instead:\n\n```ts\nimport { describe, expect, it, vi } from \"vitest\";\n```\n\n`globals: true` stays on in the Vitest configs, because React Testing Library\nregisters its automatic cleanup only when the hooks exist as globals; it has no\neffect on type checking. An override in `biome.jsonc` sets\n`noRestrictedImports` for every file on the test-only modules: `vitest`,\n`react-dom/test-utils`, `@testing-library/*` and the `act` named import of\n`react`. A second override lifts it for tests and test support, so production\ncode in any package fails `biome check` when it imports one of them. The React\nhelpers matter most, because nothing else catches them: they type-check, build\nand pass the unit tests, but `act` delegates to `React.act`, which the\nproduction build of React leaves out, so the call throws only in a packaged\napplication. A new kind of test-support path, or a new test-support package\nbuilt on Testing Library, needs adding to the second override.\n\nCommon code uses only what both environments have: `globalThis.crypto`,\n`TextEncoder`, `URL`, `AbortController`, `structuredClone`, timers. Write\n`globalThis.` when in doubt. The extension-side version of the same rule is in\nthe source-layout section of `docs/extensions/migrating-from-v1.md`.\n\n### How the check works\n\n`scripts/type-check-environments.mjs` runs both programs and counts only the\nerrors in a program's own files, the ones its `include` classifies. A program\nalso holds every file its files import, including the other environment's\nfiles and other packages, and their errors there say nothing about the\nenvironment rule; the combined program checks those files in full.\n\nFiles that failed the check when it was introduced are on the legacy lists in\n`scripts/type-check-environments/legacy.jsonc`: main or common files that need\nDOM, and renderer or common files that need Node, which the node-integrated\nrenderer still allows. Their errors are tolerated. **The lists may only\nshrink:** never add a file to make a new error pass. When a listed file stops\nfailing, the check fails until it is removed from its list.\n\n`scripts/type-check-environments/expected-failures/` proves that the programs\nstill reject what they should: every line there that must fail carries\n`@ts-expect-error`, so a program that lets it through reports an unused\ndirective. Its `main/`, `renderer/` and `common/` subdirectories fall into the\nprograms by the same rule as the sources.\n\nTwo things in the dependencies would otherwise defeat the programs silently;\nthe expected-failure files catch both if they come back:\n\n- A declaration file with `/// <reference types=\"node\" />`, and winston,\n  electron and undici all have one, loads `@types/node` into any program that\n  reaches it, whatever `types` says. The renderer program sets `typeRoots` to\n  `scripts/type-check-environments/renderer-type-roots/`, whose empty `node`\n  package absorbs those references.\n- A declaration file with `/// <reference lib=\"dom\" />` adds DOM to any program\n  that reaches it, whatever `lib` says. The main program reaches renderer code\n  through type imports, so the pnpm patch of `@xterm/xterm` removes that line\n  from its typings. A new dependency with the same line needs the same\n  treatment.\n\nDOM _type_ names such as `HTMLElement` still resolve in the main program,\nbecause `@types/react` declares empty stand-ins for them; values such as\n`document` and `window` do not.\n\n### The editor\n\nVS Code uses the root `tsconfig.json`, which has DOM and Node together, for\nevery file. The environment programs are a CI check the editor does not\nreflect: a Node global in renderer code shows no type error in the editor and\nfails `pnpm type:check`.\n\nBiome covers part of the gap while you type. An override in `biome.jsonc`\nturns on `noNodejsModules` for the `renderer/`, `renderer-api/`, `common/` and\n`common-api/` files of `freelens/src` and `packages/core/src`, classified by\nthe same path rule as the renderer program and with the same test files left\nout. It catches **imports** of Node builtins (`node:fs`, `path`, …), so the\nBiome extension flags them in the editor and `biome check` fails on them. It\ndoes not catch **Node globals** such as `Buffer`, `process`, `__dirname` or\n`NodeJS.*` types, and it does not look at the files that carry no context in\ntheir path; only `pnpm type:check` catches those.\n\nThe files that import a Node builtin today are exempted in a second override,\nwhich turns the rule off for them. Every one of them is also on the renderer\nlegacy list, and `scripts/type-check-environments.mjs` fails when an exempted\nfile is not, so the exemptions can only shrink with that list: remove a file\nfrom both when you move its Node import out.\n\nEvery path in the `includes` of a `biome.jsonc` override starts with `**/`,\nnegated ones included (`!**/packages/core/src/...`). Trunk Check, which is what\nruns Biome in CI, runs it from a sandbox outside the repository with\n`--config-path` pointing back at `biome.jsonc`, and there a pattern anchored at\nthe repository root matches no file, so the override silently does nothing.\nA plain `biome check` from the repository root matches both forms, so only\n`trunk check` shows the difference. `scripts/type-check-environments.mjs`\nchecks every path of every override and fails on one that is neither `**` nor\nstarts with `**/` or `!**/`.\n\n## Knip\n\n`pnpm knip:check` runs knip in two passes, both for dependencies. CI runs it\nafter `pnpm build`, so run a build first.\n\n- The development pass, `pnpm knip:development`, also reports **unused\n  files**: a module, barrel or stylesheet that no entry reaches. Stylesheets\n  count, because the `project` globs of the packages with styles include\n  `scss` and `css`, and knip follows both the side-effect imports in\n  TypeScript and `@use` in SCSS.\n- The production pass, `pnpm knip:production`, runs with `--production\n  --strict` over the entries marked with `!` in `knip.jsonc`, the code that\n  reaches the bundles. In it only `dependencies` count. It does not check\n  files: from the `!` entries alone, the test support and the development\n  scripts count as unused.\n\nWhen the file check reports a file, remove it rather than ignore it. Before\nyou do, check that nothing reaches it in a way knip cannot see, and that\n`pnpm type:check` and the tests still pass without it. A file that is reached\nthat way, through a config path built at runtime, a `tsconfig.json` `include`\nor a `meta.load-css()`, gets an entry in `knip.jsonc` instead, with a comment\nsaying how it is reached. A `register-injectables.ts` that nothing imports is\nthe generator's output and gets an ignore: removing it only makes\n`pnpm build:di` write it again.\n\nBoth passes run with `--no-gitignore`, because the dependency check reads the\nbundled `freelens/static/build/main.js` to find the packages the main bundle\nleaves external. The file check therefore also sees build output and local\nfiles; `knip.jsonc` ignores the build output nothing imports and the local\nartifacts of the MCP servers and of coverage. One config serves both passes,\nso `--no-config-hints` hides the hints about entries only one pass needs.\n\nThe check leaves out unused exports and types, and knip cannot report the\nunused classes inside a stylesheet.\n\n## Dependency Injection System\n\nThis project uses `@ogre-tools/injectable` for dependency injection with an **explicit registration system** that replaces the old webpack-based auto-registration. All injectable registrations are generated by `pnpm build:di`.\n\n### Registration Hierarchy\n\nThe system has three levels of registration files:\n\n1. **Leaf registration files** - Register individual injectables\n   - Example: `features/preferences/renderer/close-preferences/register-injectables.ts`\n   - Pattern: Import injectable definitions and call `di.register()`\n   - Each call wrapped in try-catch for idempotency\n\n2. **Aggregator registration files** - Register subdirectories\n   - Example: `features/preferences/renderer/register-injectables.ts`\n   - Pattern: Import and call `registerXxxInjectables(di)` from subdirectories\n   - Each call wrapped in try-catch to handle duplicates\n\n3. **Root registration files** - Entry points per process\n   - `register-injectables-main.ts` - Main process\n   - `register-injectables-renderer.ts` - Renderer process\n   - Called during DI container initialization\n\n### Directory Patterns\n\n#### Shared Aggregators\n\nDirectories with `register-injectables.ts` that aggregate subdirectories:\n\n```text\nfeatures/vars/\n├── register-injectables.ts     ← Shared aggregator (calls common/)\n├── common/\n│   └── register-injectables.ts\n└── build-version/\n    ├── main/register-injectables.ts      ← Process-specific (NOT aggregated)\n    └── renderer/register-injectables.ts  ← Process-specific (NOT aggregated)\n```\n\n**Key insight:** Shared aggregators only handle **shared** subdirectories (like `common/`). They do NOT aggregate **process-specific** subdirectories (`main/`, `renderer/`).\n\n#### Process-Specific Paths\n\nPaths containing `/main/` or `/renderer/` are process-specific and must be imported directly:\n\n- ✅ Include: `features/vars/build-version/main/register-injectables`\n- ❌ Exclude: `features/vars/common/register-injectables` (handled by parent aggregator)\n\n### When to Re-run Generation\n\nRun `pnpm build:di` when:\n\n- Adding new injectable files\n- Moving injectable files\n- Renaming injectable files\n- Changing directory structure\n- Modifying generation script\n\nThe build process automatically runs this, but you can run it manually to verify changes.\n\n### Bundled Binary Versions\n\nThe versions of the bundled `freelens-k8s-proxy`, `kubectl` and `helm` live in\nthe `config` block of `freelens/package.json`, and their exact digests are\npinned in `freelens/binaries.lock.json`. The build reads the expected checksum\nfrom that lock rather than from the vendor, so **a version bump without\nregenerating the lock fails the build**:\n\n```sh\npnpm update-binaries-lock\n```\n\nThe generator downloads all eighteen artifacts (three tools, three platforms,\ntwo architectures), checks each against its publisher's signature — GitHub build\nprovenance for freelens-k8s-proxy, PGP for helm, keyless cosign for kubectl —\nand only then writes the lock. `cosign` comes from mise (`mise install`), and\n`GITHUB_TOKEN` should be set unless you want to share 60 unauthenticated API\ncalls per hour with the rest of your IP. Use `--only <tool>` to refresh a single\ntool while iterating.\n\nhelm is downloaded as a tarball, so its `sha256` pins the archive and a second\ndigest, `binarySha256`, pins the binary extracted from it. The build hashes\nevery file already in `freelens/binaries/` against the lock on each run and\ndownloads it again on a mismatch; it keeps no record of what it verified\nbefore. That is what makes the directory safe to restore from a CI cache:\nwhoever could write a binary into the cache could write such a record too.\nFor the same reason the binaries are not an output of a cached Turbo task: the\nTurbo cache would restore them without the check. `build:binaries` runs\nuncached on every build instead, which costs only the hashing when the\nbinaries are in place.\n\n`.github/workflows/binaries-lock-check.yaml` enforces both that the lock is\ncurrent and that no digest changed while its version stood still. On a\nRenovate branch a stale lock does not fail the check: Renovate bumps the\nversion but cannot run the generator, so the workflow regenerates the lock,\nchecks it for replaced artifacts, and commits it to the branch with `GH_TOKEN`,\nwhich starts the checks again on the new commit.\n\n### Downloaded kubectl Versions\n\nThe bundled kubectl is not the only one the application runs: a cluster whose\nminor version differs gets a version-matched kubectl downloaded at runtime. The\nmap of which patch to fetch per minor lives in\n`packages/kubectl-versions/build/versions.json`, and the digest of every\nartifact that map can produce is pinned in\n`packages/kubectl-versions/build/checksums.json`, keyed by version and then by\n`${platform}/${arch}`.\n\n`Kubectl.downloadKubectl()` hashes what it downloaded and refuses anything that\ndoes not match its pin, and `ensureKubectl()` refuses to download at all when\nthere is no pin, falling back to the bundled binary. **A version added to the\nmap without a pin therefore never gets downloaded**, so the two files are\nregenerated together:\n\n```sh\npnpm --filter @freelensapp/kubectl-versions compute-versions\npnpm update-kubectl-checksums\n```\n\nThe generator reads `dl.k8s.io` only, never a mirror — pinning bytes from a\nmirror would let a compromised mirror bless its own digest. It skips versions\nalready present, which makes a run incremental and an existing pin immutable,\nand it verifies each download against both the published `.sha256` and the\nkeyless cosign signature before recording it. `cosign` comes from mise\n(`mise install`).\n\nBoth files start at 1.22, the oldest line Kubernetes publishes a signature for,\nand coverage is not uniform below that floor's neighbours: v1.22.17 has no\n`windows/arm64` build, so the generator logs an unpublished variant and carries\non rather than failing. `.github/workflows/kubectl-checksums-check.yaml`\nverifies added pins and asserts that no existing digest changed.\n\n### Development Tools (mise)\n\nThe development tools (`cosign`, `node`, `yq`) are declared in `mise.toml` and\npinned with their checksums in `mise.lock`. The lock uses lockfile format\nversion 3 (`lockfile_version = 3`), which **needs mise 2026.9.16 or newer**: an\nolder mise rejects the lock, so `mise install` fails until mise is upgraded.\n\nAfter changing a version in `mise.toml`, regenerate the lock with `mise lock`,\nwhich refreshes every tool on every platform in the file. `mise install`\nre-locks only the platform it runs on and leaves the others stale.\n\n## Common Development Tasks\n\n### Adding a New Feature\n\n1. Create feature directory under `packages/core/src/features/`\n2. Organize by concern: `common/`, `main/`, `renderer/`\n3. Create injectable files with `.injectable.ts` suffix\n4. Run `pnpm build:di` to generate registration files\n5. Write tests alongside implementation\n\n### Debugging the Application\n\n**Main Process:**\n- Logs in terminal where `pnpm start` was run\n- Use `console.log()` or proper logger\n\n**Renderer Process:**\n- Open DevTools in the app\n- Check Console tab for errors and logs\n- Use React DevTools for component inspection\n- `pnpm dev` also exposes a Chrome DevTools Protocol endpoint on port 9223\n  (`--remoteDebuggingPort`). Note that each cluster's UI renders in a\n  cross-origin `<clusterId>.renderer.freelens.app` iframe, so inspecting or\n  automating cluster views requires a frame-aware CDP client — see the\n  AI-agent inspection notes in DEVELOPMENT.md.\n\n**Common Errors:**\n- `Tried to register same injectable multiple times` - See DI section above\n- `Tried to inject non-registered injectable` - Check registration files were\n  generated. In a unit test, a newly added `*.injectable.ts` can report this\n  even when the file exists and `pnpm build:di` ran: `getDiForUnitTesting`\n  registers through `import.meta.glob(..., { eager: true })`, and\n  `node_modules/.vitest-cache` keeps the glob expanded over the files that\n  existed when it was first cached. Clear it (`rm -rf node_modules/.vitest-cache`)\n  and re-run.\n- Permission errors on macOS - Expected during development\n\n### Working with the bundler (electron-vite)\n\nThe project bundles with electron-vite (Vite + Rollup); the legacy Webpack\nlayer was removed in #2118.\n\n- `freelens/electron.vite.config.ts` - main/renderer build and dev-server config\n- `pnpm dev` runs `electron-vite dev` with Vite HMR; renderer source changes\n  hot-reload, main-process changes rebuild and relaunch (via `--watch`)\n- Changes to generated files (e.g. DI registration) require a full rebuild\n\n**Cache issues:** Delete the build output and rebuild\n(`rm -rf .turbo packages/core/dist freelens/dist`)\n\n### The Electron binary\n\n`pnpm install` leaves the `electron` package without its runtime binary. The\npackage has no `postinstall` script, so `electron: true` in `allowBuilds` has\nnothing to run; it downloads the binary lazily instead, when\n`require(\"electron\")` or its `electron` bin finds `path.txt` missing.\nelectron-vite does not go through either: it reads\n`node_modules/electron/path.txt` itself and throws `Electron uninstall` when\nthe file is absent, so `electron-vite dev` alone never triggers the download.\n\nThe `predev` script of `freelens/package.json` therefore runs the package's\n`install-electron` bin (`electron/install.js`) before `electron-vite dev`.\n`install.js` exits at once when the binary of the installed version is\nalready in place, and otherwise downloads it, verifies it against the\npackage's `checksums.json` and writes `path.txt`. pnpm runs `pre` scripts for\n`pnpm run dev`, both inside `freelens/` and through the root `turbo run dev`,\nwhich invokes `pnpm run dev` in the package.\n\nThe `dev` script is for local development only. CI does not use it: the\nworkflows that need the binary run `electron/install.js` explicitly, as a\nseparate step, before tests or the build.\n\n## Troubleshooting Patterns\n\n### Changes Not Appearing\n\n1. Check if file is in ignored directory (`dist/`, `node_modules/`)\n2. Clear the build output: `rm -rf .turbo packages/core/dist freelens/dist`\n3. Full rebuild: `pnpm build`\n4. Restart application: `pnpm start`\n\n### Build Failures\n\n1. Check for TypeScript errors: `pnpm type:check` (see \"Runtime Environments in\n   Type-Checking\" when the main or renderer program fails)\n2. Check for linting errors: `pnpm lint`\n3. Verify dependencies: `pnpm install`\n4. Check Node.js version matches `.nvmrc`\n\n### Runtime Errors\n\n1. Check dev console (renderer) or terminal (main)\n2. Look for stack traces with file:line numbers\n3. Verify all dependencies are registered (DI system)\n4. Check for circular dependencies\n\n## Architecture Decisions\n\n### Electron Multi-Process\n\n- **Main process** - Node.js environment, system access\n- **Renderer process** - Chromium browser, UI\n- **IPC** - Communication between processes\n\n### Feature Organization\n\nFeatures are self-contained modules with:\n- Domain logic\n- UI components\n- State management\n- Injectable definitions\n\n### Monorepo Structure\n\nUses pnpm workspaces for:\n- Shared code reuse\n- Faster builds\n- Type safety across packages\n\n## Styling\n\nFreelens carries four styling systems (theme CSS custom properties, global\nplain SCSS, CSS Modules, and Tailwind v4). Which one to use is not a matter of\ntaste — each has a defined role. Before adding or changing any stylesheet or\n`className`, read [`docs/styling.md`](./docs/styling.md). In short:\n\n- **Theme values** (colors, fonts): CSS custom properties from the TS theme\n  system (`var(--…)`) — the single contract every other system reads.\n- **Shared components** (`packages/ui-components`) and anything an extension\n  may restyle: global PascalCase class + plain SCSS + `var(--…)`. No Tailwind\n  (its JIT only scans core TSX), no CSS Modules (the class names are public\n  API).\n- **Core single components / full views**: CSS Modules (`*.module.scss`).\n- **Local layout inside core-only TSX**: Tailwind utilities. The legacy\n  `flexbox.scss` utilities have been removed — do not reintroduce them.\n- **Extensions**: see the styling section of\n  [`docs/extensions/migrating-from-v1.md`](./docs/extensions/migrating-from-v1.md).\n\n## Extension API\n\nThe extension specification lives in three documents, and which one to read\ndepends on the question:\n\n- [`docs/extensions/api.md`](./docs/extensions/api.md) — the **normative\n  contracts**. Each states the guarantee, the stable surface and the failure\n  mode. Read this before changing anything under `packages/extensions/` or\n  `packages/core/src/extensions/`.\n- [`docs/extensions/binaries.md`](./docs/extensions/binaries.md) — what an extension\n  may **ship and execute** besides JavaScript, and what the host does with it.\n- [`docs/extensions/migrating-from-v1.md`](./docs/extensions/migrating-from-v1.md) — the\n  author-facing **porting guide** from v1.\n\nThe agent skills of freelensapp/freelens-example-extension,\n`create-freelens-extension` and `port-freelens-extension-to-v2`, link to these\ndocuments on `main` and cite their sections by name. So does the template of\nthe v2 migration issue that a port copies,\n`skills/port-freelens-extension-to-v2/references/migration-issue.md`, except\nthat its links are pinned to a commit of this repository. Renaming or removing\none of the sections below therefore needs a matching change to the `SKILL.md`\nfiles under `skills/` in that repository, and to that template when its pin\nmoves to a commit with the change:\n\n- in `api.md`, the contracts C1 to C15 by number as a range, and C3\n  (host-provided singletons), C6 (registration), C9 (routing), C10 (styling\n  and CSS), C12 (HTTP) and C15 (the host's kubectl, helm and terminal\n  environment) on their own;\n- in `migrating-from-v1.md`, these headings:\n  - \"Step one: bump `engines.freelens`\"\n  - \"`package.json` for an extension\"\n  - \"Source layout: one tsconfig per runtime environment\"\n  - \"MobX 7 and mobx-react 10 (standard decorators only)\"\n  - \"Registering things: declarative fields\"\n  - \"Reaching a catalog cluster\"\n  - \"v1→v2 rename table\"\n  - \"Node and Electron in the renderer\"\n  - \"Styling and CSS\"\n  - \"The development loop\"\n  - \"Checklist\", and the two items at its end that it marks as failing\n    silently;\n- `binaries.md` as a whole document, by its file name;\n- in this file, the heading \"Modifying GitHub Actions Workflows\", which the\n  template cites.\n\nThree traps worth carrying without looking them up. The API surface is only what\nthe `Common` / `Main` / `Renderer` namespaces re-export — every other\n`@freelensapp/*` package is private and inlined into the published declaration,\nso a symbol that is not re-exported is unreachable by any means. And the host\nmust be the single instance of React, mobx and monaco; a second\ncopy of mobx fails **silently**, so changes there need an identity assertion\nrather than a passing test suite.\n\nThe third: the published declaration is not the source. `rolldown-plugin-dts`\nturns each module behind a namespace into a `declare namespace` that\nre-exports its members, and it drops the `type` modifier on the way. A **class\nre-exported type-only**, with `export type { C }` or `export type { C } from\n\"…\"`, is therefore declared as a value too, so `new C(…)` and `x instanceof C`\ncompile against the declaration and throw in the extension. Use a type alias\ninstead, `export type C<T> = import(\"…\").C<T>`, carrying the class's type\nparameters with their constraints and defaults.\n\nTwo guards catch a regression.\n`packages/core/src/extensions/__tests__/extension-api-declared-values.test.ts`\nwalks the built declaration with the TypeScript 7 checker\n(`typescript/unstable/sync`) and fails on every value it declares that the\nruntime namespace object does not have. The fixture extension's\n`packages/fixture-extension/src/common/contract-types.ts` names the\ntype-and-value pairs of `K8sApi`, `type X` and `const X` of the same name, as\ntypes, so its type check fails if one loses its type meaning in the bundle.\n\nThe bundle also depends on `rolldown-plugin-dts` 0.28.8 or newer, which\ntree-shakes a namespace import whose members a declaration names only by\nqualified name, such as `import * as utilities` in `common-api/utils.ts`. An\nolder version keeps every member of the module in the bundle. That includes\nthe Node-bound members `Common.Util` leaves out, with their `node:` imports.\n`build:dist` of `@freelensapp/extensions` fails when the bundle imports a Node\nbuiltin or references Node's types, and names that tree-shaking as the likely\ncause, so a regression in the plugin fails the build rather than reaching an\nextension.\n\n## Best Practices\n\n1. **Always regenerate DI files** after adding/moving injectables\n2. **Full rebuild** when in doubt about cached state\n3. **Check both processes** when debugging (main + renderer)\n4. **Use semantic search** to find examples in codebase\n5. **Follow existing patterns** - grep for similar implementations\n6. **Test changes** before committing\n7. **Run validation after file changes (especially before commit):** run `trunk check` (or `pnpm trunk check` if `trunk` is not installed locally)\n8. **For main project TypeScript and HTML files:** run `pnpm biome check` (`--write` to apply the fixes). Biome is not a dependency of the project: the `biome` script of the root `package.json` runs the pinned version through `pnpm dlx`. A bare `biome` or `pnpm exec biome` runs whatever `biome` is on `PATH`, such as a Homebrew one, whose version may format differently and rewrite code the change does not touch.\n9. **For other file types:** use `trunk check` (or `pnpm trunk check` if `trunk` is not installed locally)\n10. **Do not use Antropic Fable for coding tasks** — Fable may be used only for planning,\n    analysis, and thinking through problems. When writing or editing code,\n    use standard editing tools instead.\n\n## Local Agent: Triggering the GitHub Agent\n\nThese rules apply to an agent running on a developer machine (a local Claude\nCode session), not to the workflow agent. The local agent shares the repository\nwith the CI agent defined in `.github/workflows/claude.yaml`, and every comment\nit writes on GitHub is a potential trigger for it.\n\n### How the trigger works\n\n`claude.yaml` starts a run when the body of a **newly created** comment (issue\ncomment or PR review comment), a **newly opened** issue (body or title), or a\n**submitted** PR review contains the string `@claude`, and its author has\nwrite access to the repository (the admin, maintain or write role). The\nworkflow condition pre-filters on OWNER, MEMBER or COLLABORATOR, which does not\nimply write access, and the first step of the run checks the actual\npermission; a run triggered by anyone else fails there. The check is a plain\n`contains(github.event.comment.body, '@claude')` substring test, so the string\nfires the workflow wherever it appears — including inside a code span, a fenced\nblock, a quoted line, or a URL. Markdown formatting is not an escape.\n\nThe trigger text may also carry `[model:<alias>]`, `[effort:<level>]` and\n`[runs-on:<alias>]` markers, which select the model, the reasoning effort and\nthe runner for that run (see the `parse` job for the accepted aliases). They are\nonly read from the triggering text.\n\nThe default model is `claude-opus-5-5[1m]` (Opus 5.5 with the 1M-token\ncontext) and it runs at `high` effort. Naming a model explicitly drops that\ndefault: the run then uses the CLI default effort unless `[effort:...]` also\nsays otherwise. Accepted levels are `low`, `medium`, `high`, `xhigh` and\n`max`; anything else is ignored with a note in the job log.\n\n### Rules for the local agent\n\n1. **Write the handle only to start a run.** Ask the user before triggering: a\n   run is a 120-minute CI job on the repository, so it is the user's call, not\n   an implementation detail.\n2. **Escape the handle when merely referring to it.** In issue bodies, PR\n   descriptions, review notes, commit messages and documentation, write\n   `@<!-- -->claude` (displays as the handle, but the raw body does not contain\n   the literal string, so `contains()` does not match) or describe it in prose\n   as \"the Claude handle\". This is what keeps a plan or a bug report that\n   documents the trigger from firing it.\n3. **Editing never triggers.** The workflow subscribes only to `created`,\n   `opened` and `submitted` events — not `edited`. So updating a comment, an\n   issue body or a PR description is always safe, even when the text already\n   contains a real trigger, and conversely editing a comment to add the handle\n   does **not** start a run: a new comment is required.\n4. **One trigger per task.** Do not repeat the handle in follow-up comments\n   while a run is in flight; each occurrence starts another concurrent job.\n5. **Push first.** The workflow checks out the remote ref (the PR head, or the\n   default branch for issues), so anything not pushed is invisible to it.\n\n## GitHub Actions (Claude Code Action) Rules\n\nWhen operating via the `claude.yaml` workflow (i.e., invoked from a PR comment,\nissue, or review), follow these rules:\n\n### Code Review\n\nWhen reviewing code and proposing fixes:\n\n1. **Show the diff first** — present every proposed change as a unified diff\n   block using the `diff` language tag:\n\n   ```diff\n   --- a/path/to/file.ts\n   +++ b/path/to/file.ts\n   @@ -10,7 +10,7 @@\n    const oldLine = \"before\";\n   -const changedLine = \"after\";\n   +const changedLine = \"the fix\";\n    const unchangedLine = \"same\";\n   ```\n\n   You can generate this from the terminal with:\n   ```bash\n   git diff -u -- path/to/file\n   ```\n\n   If the change spans multiple files, group them under a single commit\n   subject and show each file's diff sequentially.\n\n2. **Propose a commit subject first** — before any code change, output a\n   single line with the proposed commit subject:\n\n   ```text\n   **Proposed commit:** <short description>\n   ```\n\n   Do **not** use Conventional Commits prefixes (e.g. `fix:`, `feat:`,\n   `chore:`, `refactor:`, `docs:`, `test:`, `ci:`). This project prefers\n   plain, descriptive commit messages and PR titles without any prefix.\n\n   Wait for the user to confirm (or adjust) the subject before applying the\n   change.\n\n3. **Comment style:**\n   - Keep review comments concise and actionable\n   - Reference specific lines (file + line number) when pointing out issues\n   - Offer a concrete fix suggestion rather than just flagging a problem\n   - Do **not** use emoji in any Markdown, comments, commit messages, or\n     PR descriptions. The only exception is emoji that already appears\n     inside code strings (e.g. application logs, user-facing messages).\n   - Use GitHub's `suggestion` block for small targeted fixes so the PR\n     author can accept the change with a single click:\n\n     ````suggestion\n     <same unified-diff format as shown above>\n     ````\n\n   - For larger multi-file changes, use `diff -u` blocks in a regular\n     comment instead, with the proposed commit subject shown first\n\n### Making Changes to a PR\n\nWhen asked to implement a change on a PR:\n\n1. Propose the commit subject (as above)\n2. Describe what will change and why\n3. After confirmation, apply the changes with commits on the PR branch\n4. **One commit per fix** — when a review surfaces more than one issue or\n   the plan includes more than one fix, apply and commit each fix\n   separately. Do not batch multiple independent fixes into a single\n   commit. This keeps the history bisectable and makes each change easy\n   to revert individually.\n\n### Pushing After Every Commit\n\nThe GitHub Actions job running Claude has a total timeout of 120 minutes.\nWhen the session times out, any commits that exist only in the runner's\nlocal checkout are lost. To make the work resumable in a follow-up session:\n\n1. **Push to the remote branch immediately after every commit.** Do not\n   accumulate multiple local commits before pushing — commit, push, then\n   move on to the next change.\n2. This pairs with the \"one commit per fix\" rule above: each completed fix\n   should land on the remote branch as soon as it is committed, so a\n   timed-out session can be resumed from the last pushed commit instead of\n   starting over.\n3. **Run every command in the foreground.** The workflow runs Claude\n   headless: the session ends as soon as the agent ends its turn, and\n   nothing wakes it up when a background command finishes. A build, a\n   test run or `trunk check` started in the background and then waited on\n   is killed with the job, together with every uncommitted change. Give\n   long commands a foreground timeout (up to ten minutes) instead, and\n   commit and push what is done before starting a long validation.\n\n### Force-Pushing a Rewritten Branch\n\nWhen you are asked to rebase a pull request branch, or to rewrite its\nhistory in another way (amend, squash, drop a commit), push the result with:\n\n```bash\ngit push --force-with-lease origin HEAD\n```\n\nThe push wrapper the action names in its instructions, `git-push.sh`, accepts\nno flags, so it cannot do this; `git` itself is allowed in this workflow.\nDo not fall back to merging `main` into the branch instead: a merge commit is\nnot what was asked for.\n\nForce-push only the pull request branch the run was invoked on, and only when\nthe request calls for a rewrite. Never force-push `main` or any other branch,\nand never rewrite a history you were not asked to.\n\n### Modifying GitHub Actions Workflows\n\nClaude cannot push changes to files under `.github/workflows/` directly,\nbecause the GitHub token used by the action lacks the `workflows` permission.\nAny patch to a workflow file MUST therefore be delivered as a new, complete\nfile under the `github-workflow-fix/` directory instead of editing the file in\nplace:\n\n1. Write the full, final contents of the workflow to\n   `github-workflow-fix/<workflow-file-name>` (e.g.\n   `github-workflow-fix/claude.yaml`). Do **not** edit the original file under\n   `.github/workflows/`.\n2. Make it a **complete** file — the entire workflow as it should look after\n   the change, not just a diff or fragment — so it can be copied verbatim.\n3. Commit and open the PR as usual. In the PR description, clearly note that\n   the file is a proposed workflow change and that a maintainer must move it\n   from `github-workflow-fix/` to `.github/workflows/` manually.\n\nThis lets the PR be created successfully while leaving the actual workflow\nchange for a human to apply.\n\n### Branch Naming\n\n**Work on the branch the workflow put you on.** Do not rename it, and do not\nmove the work to a better-named branch.\n\n`claude-code-action` creates the branch itself, as\n`claude/issue-<number>-<date>-<time>`, and the workflow passes it no name to\nuse instead. Its comment header — the branch link and the \"Create PR\" link —\nis written from that name. So an agent that moves to a different branch leaves\nthe header pointing at an abandoned one, leaves a stray branch behind, and\nspends part of its run on a rename instead of the task. This guide used to\nrequire a readable name and forbid the timestamp, which produced exactly that\nevery time.\n\nIf you are creating a branch yourself, with no workflow-provided one, use\n`claude/<short-slug>`.\n\nThe branch name is not worth managing: it lives for a few hours and the pull\nrequest is what anyone refers to afterwards.\n\n### PR Title Conventions\n\nWhen creating a PR, use the following title conventions:\n\n- **Agent-related changes** — PRs whose changes are strictly related to coding\n  agent configuration (e.g. `AGENTS.md`, `.github/workflows/claude.yaml`, or\n  other files that govern how Claude operates in this repository) MUST use\n  the prefix `Claude:` (followed by a space) in the title.\n\n  Examples:\n  - `Claude: Add rule for PR title conventions in AGENTS.md`\n  - `Claude: Update claude.yaml workflow permissions`\n\n- **All other PRs** — do **not** use any prefix (no `fix:`, `feat:`, `chore:`,\n  etc.). Use plain, descriptive titles.\n\n### Fork PRs: Review Only\n\nA PR from a fork (different owner than `freelensapp`) gets a review and\nnothing else: no commits, no pushes, no branches. Its code is untrusted, and\nthe head of a fork PR can change between the moment a maintainer looks at it\nand the moment the workflow checks it out, so nothing taken from the checkout\nmay reach `freelensapp/freelens`.\n\nWhen a fork PR needs changes, a maintainer first copies the exact commit they\nreviewed to a branch in this repository. From then on it is a\nsame-repository PR, which gets the full setup and the normal workflow. The\ncopy is made either locally (`gh pr checkout <N>`, then push the branch) or\nby the Claude Task workflow, following \"Copying a Fork PR\" below.\n\n### Copying a Fork PR\n\nThis applies to a Claude Task run whose prompt asks to copy a fork PR and\nnames the PR number and the full commit SHA to copy. It is a git-only task:\ndo not check out, read, build or run any of the PR's files, and do not\ndescribe its changes, because they are untrusted input.\n\n1. `git fetch origin refs/pull/<N>/head`.\n2. Verify that `FETCH_HEAD` equals the given SHA. If it does not, or no full\n   SHA was given, stop and report the actual head without pushing anything.\n3. `git push origin <sha>:refs/heads/claude/pr-<N>`.\n4. Open a PR from `claude/pr-<N>` to `main`. It MUST use the **exact same\n   title** as the original PR, copied verbatim with no prefix, and its body\n   is `Copy of #<N> at <sha>.` followed by the usual footer.\n5. Comment on the original PR with a link to the new one.\n\n### Closing PRs\n\nClaude may only close a PR when ALL of the following are true:\n\n1. The PR was created by Claude from a `claude/` branch, OR the PR is the\n   original fork PR that a copy supersedes (see \"Copying a Fork PR\" above).\n2. The close reason is explicitly explained in a comment on the PR.\n\nClaude MUST NOT close any PR that does not meet these conditions — even if\nasked. Instead, explain to the requester why the PR cannot be closed\nautomatically and ask a human maintainer to close it manually.\n\n### Model Information in Comments\n\nWhen operating via the GitHub Actions workflow, always include the model you are\nrunning on in the footer of your GitHub comment and in the PR description when\ncreating a pull request, alongside the job run link.\nYour system environment context states the model name explicitly (e.g.\n\"You are powered by the model named Sonnet 4.6. The exact model ID is\nclaude-sonnet-4-6.\"). Use the exact model ID from that statement.\n\nFormat the footer line as:\n\n```text\n[View job run](...) | Model: `claude-sonnet-4-6`\n```\n\nIn a PR description, append the model information at the end of the body:\n\n```text\n| Model: `claude-sonnet-4-6`\n```\n\nIf the system context does not provide a model ID, omit the model field rather\nthan guessing.\n\n### Development Environment\n\nThe GitHub Actions runner has a full Node.js + pnpm environment available, and\nthe workflow attempts to install the dependencies (`pnpm install`), the\n`trunk` CLI and mise, with the `cosign` and `yq` that `mise.lock` pins, before\nstarting Claude. The build step is skipped to save CI resources, but you can\nrun build commands when needed for advanced tasks (e.g. type-checking, running\ntests).\n\nEvery one of those setup steps is `continue-on-error`, so any of them may have\nfailed and left its tool or `node_modules` missing. Verify that what you need\nis actually there before relying on it, and never report a check as passing\nwhen it did not run — say that it was unavailable instead.\n\nThe `origin` remote is always `freelensapp/freelens`, for fork PRs too: their\ncommits are checked out through the pull ref.\n\nA PR from a fork runs in review mode, because its code is untrusted and the\njob holds write tokens. None of the setup above runs, and the tools that\nexecute the repository's code (`pnpm`, `node`, `npx`, `bash`, `trunk`,\n`mise`), edit files or commit and push are not available. Review the code by\nreading it, and say that no check ran. See \"Fork PRs: Review Only\" for how a\nfork PR that needs changes is handled.\n\nThe following CLI tools are explicitly allowed in the workflow:\n\n- `pnpm` (all subcommands) — for validation, formatting, and builds\n- `git` (all subcommands) — for viewing changes, creating branches,\n  committing, and pushing\n- `gh` (all subcommands) — for managing pull requests\n- `trunk` — for linting and formatting every non-TypeScript file type\n- `mise` — for regenerating `mise.lock` (`mise lock`) after a version bump in\n  `mi\n\n<!-- File: packages/business-features/keyboard-shortcuts/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Keyboard-shortcuts Skill\n\nPath: `packages/business-features/keyboard-shortcuts/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/business-features/keyboard-shortcuts/package.json)\n\n<!-- File: packages/business-features/keyboard-shortcuts/tsconfig.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Keyboard-shortcuts Skill\n\nPath: `packages/business-features/keyboard-shortcuts/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/business-features/keyboard-shortcuts/tsconfig.json)\n\n<!-- File: packages/cluster-settings/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Cluster-settings Skill\n\nPath: `packages/cluster-settings/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-settings/package.json)\n\n<!-- File: packages/cluster-settings/tsconfig.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Cluster-settings Skill\n\nPath: `packages/cluster-settings/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-settings/tsconfig.json)\n\n<!-- File: packages/cluster-sidebar/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Cluster-sidebar Skill\n\nPath: `packages/cluster-sidebar/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-sidebar/package.json)\n\n<!-- File: packages/cluster-sidebar/tsconfig.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Cluster-sidebar Skill\n\nPath: `packages/cluster-sidebar/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/cluster-sidebar/tsconfig.json)\n\n<!-- File: packages/core/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Core Skill\n\nPath: `packages/core/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/core/package.json)\n\n<!-- File: packages/core/tsconfig.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Core Skill\n\nPath: `packages/core/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/core/tsconfig.json)\n\n<!-- File: packages/ensure-binaries/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Ensure-binaries Skill\n\nPath: `packages/ensure-binaries/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ensure-binaries/package.json)\n\n<!-- File: packages/ensure-binaries/tsconfig.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Ensure-binaries Skill\n\nPath: `packages/ensure-binaries/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/ensure-binaries/tsconfig.json)\n\n<!-- File: packages/extensions/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Extensions Skill\n\nPath: `packages/extensions/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/extensions/package.json)\n\n<!-- File: packages/extensions/tsconfig.dts.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Extensions Skill\n\nPath: `packages/extensions/tsconfig.dts.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/extensions/tsconfig.dts.json)\n\n<!-- File: packages/extensions/tsconfig.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Extensions Skill\n\nPath: `packages/extensions/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/extensions/tsconfig.json)\n\n<!-- File: packages/generate-license/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Generate-license Skill\n\nPath: `packages/generate-license/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-license/package.json)\n\n<!-- File: packages/generate-license/tsconfig.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Generate-license Skill\n\nPath: `packages/generate-license/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-license/tsconfig.json)\n\n<!-- File: packages/generate-tray-icons/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Generate-tray-icons Skill\n\nPath: `packages/generate-tray-icons/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-tray-icons/package.json)\n\n<!-- File: packages/generate-tray-icons/tsconfig.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Generate-tray-icons Skill\n\nPath: `packages/generate-tray-icons/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/generate-tray-icons/tsconfig.json)\n\n<!-- File: packages/infrastructure/typescript/config/base.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Config Skill\n\nPath: `packages/infrastructure/typescript/config/base.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/infrastructure/typescript/config/base.json)\n\n<!-- File: packages/infrastructure/typescript/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Typescript Skill\n\nPath: `packages/infrastructure/typescript/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/infrastructure/typescript/package.json)\n\n<!-- File: packages/kube-object/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Kube-object Skill\n\nPath: `packages/kube-object/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kube-object/package.json)\n\n<!-- File: packages/kube-object/tsconfig.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Kube-object Skill\n\nPath: `packages/kube-object/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kube-object/tsconfig.json)\n\n<!-- File: packages/kubectl-versions/build/checksums.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Build Skill\n\nPath: `packages/kubectl-versions/build/checksums.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/build/checksums.json)\n\n<!-- File: packages/kubectl-versions/build/tsconfig.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Build Skill\n\nPath: `packages/kubectl-versions/build/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/build/tsconfig.json)\n\n<!-- File: packages/kubectl-versions/build/versions.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Build Skill\n\nPath: `packages/kubectl-versions/build/versions.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/build/versions.json)\n\n<!-- File: packages/kubectl-versions/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Kubectl-versions Skill\n\nPath: `packages/kubectl-versions/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/package.json)\n\n<!-- File: packages/kubectl-versions/tsconfig.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Kubectl-versions Skill\n\nPath: `packages/kubectl-versions/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/kubectl-versions/tsconfig.json)\n\n<!-- File: packages/list-layout/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# List-layout Skill\n\nPath: `packages/list-layout/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/list-layout/package.json)\n\n<!-- File: packages/list-layout/tsconfig.json (Tokens: ~300 | Category: anthropic-skill) -->\n# List-layout Skill\n\nPath: `packages/list-layout/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/list-layout/tsconfig.json)\n\n<!-- File: packages/logger/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Logger Skill\n\nPath: `packages/logger/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/freelensapp/freelens/HEAD/packages/logger/package.json)\n\n<!-- ... +110 more modular skills available via /api/skills/freelensapp/freelens?path={path} -->\n</yakaai_skills>"}