Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
80fe7ee
feat(extension): parse gateway usage and model context length
iscekic Jun 26, 2026
1db00b1
feat(extension): forward turn usage to callers
iscekic Jun 26, 2026
de2c3b0
feat(extension): keep drafts per conversation
iscekic Jun 26, 2026
3017a63
feat(extension): close conversation tab without confirmation
iscekic Jun 26, 2026
01e4036
feat(extension): show context usage donut in footer
iscekic Jun 26, 2026
f416496
feat(extension): add manual and automatic context compaction
iscekic Jun 26, 2026
d937464
fix(extension): block send while a conversation is compacting
iscekic Jun 26, 2026
c635f6e
test(extension): cover context donut, compaction, drafts, tab close
iscekic Jun 26, 2026
0dc265f
fix(extension): satisfy lint and typecheck in new e2e tests
iscekic Jun 26, 2026
ef82d7c
style(extension): apply oxfmt to new context files
iscekic Jun 26, 2026
da2a010
refactor(extension): drop unused compaction abort param, document com…
iscekic Jun 26, 2026
18f5a9d
fix(extension): trust side-panel sender by extension origin
iscekic Jun 26, 2026
0f7d123
test(extension): make context-usage e2e robust to compaction timing
iscekic Jun 26, 2026
15b017c
style(extension): use a block comment for the stored-auth queryFn note
iscekic Jun 26, 2026
6233aac
ci(extension): run verify, build, and e2e on extension changes
iscekic Jun 26, 2026
f1ad780
fix(extension): make manual Compact now work for short conversations
iscekic Jun 26, 2026
68a0c95
fix(extension): manual compaction summarizes the whole conversation
iscekic Jun 26, 2026
f39d70c
fix(extension): address PR review on compaction transcript and CI paths
iscekic Jun 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions .github/workflows/extension-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
name: extension CI

on:
push:
branches: [main]
paths:
Comment thread
iscekic marked this conversation as resolved.
- 'apps/extension/**'
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'
- '.nvmrc'
- '.github/workflows/extension-ci.yml'
pull_request:
branches: [main]
paths:
- 'apps/extension/**'
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'
- '.nvmrc'
- '.github/workflows/extension-ci.yml'

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

permissions:
contents: read
pull-requests: read

jobs:
# Compiler, linter, formatting and unit tests, via the extension's own `verify`
# script so the extension's stricter (type-aware) oxlint config is what runs.
verify:
runs-on: ${{ vars.RUNNER_DEFAULT_LABEL || 'ubuntu-latest' }}
timeout-minutes: 15
steps:
- uses: useblacksmith/checkout@41cdeedae8edb2e684ba22896a5fd2a3cb85db6b # v1
with:
lfs: true

- name: Setup pnpm
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0

- name: Setup Node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version-file: '.nvmrc'
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Verify (typecheck, lint, format, unit tests)
run: pnpm --filter kilo-extension verify

# Prove the Firefox MV3 target still builds (the Chrome build runs inside e2e).
build-firefox:
runs-on: ${{ vars.RUNNER_DEFAULT_LABEL || 'ubuntu-latest' }}
timeout-minutes: 15
steps:
- uses: useblacksmith/checkout@41cdeedae8edb2e684ba22896a5fd2a3cb85db6b # v1
with:
lfs: true

- name: Setup pnpm
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0

- name: Setup Node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version-file: '.nvmrc'
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build (Firefox MV3)
run: pnpm --filter kilo-extension build:firefox

# Chrome end-to-end tests. `e2e:chrome` builds the Chrome MV3 bundle first, so this
# also covers the Chrome build. Firefox Selenium e2e (`e2e:firefox`) is intentionally
# not run here: it relies on geckodriver tab detection that is unreliable headless.
e2e-chrome:
needs: verify
runs-on: ${{ vars.RUNNER_LARGE_LABEL || 'ubuntu-24.04-8core' }}
timeout-minutes: 20
env:
CI: 'true'
steps:
- uses: useblacksmith/checkout@41cdeedae8edb2e684ba22896a5fd2a3cb85db6b # v1
with:
lfs: true

- name: Setup pnpm
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0

- name: Setup Node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version-file: '.nvmrc'
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Install Playwright Chromium
run: pnpm --filter kilo-extension exec playwright install --with-deps chromium

- name: Run Chrome e2e (builds the Chrome MV3 bundle first)
run: pnpm --filter kilo-extension e2e:chrome

- name: Upload Playwright report on failure
if: failure()
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: extension-playwright-report
path: |
apps/extension/playwright-report
apps/extension/test-results
retention-days: 7
if-no-files-found: ignore
19 changes: 15 additions & 4 deletions apps/extension/entrypoints/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,27 @@ interface ChromeRuntimeApi {
/*
* Trust boundary for the eval/debugger message path. Today only the extension's own pages (the
* side panel) can reach this listener — there is no externally_connectable and no content script.
* Accept only same-extension, non-tab senders so adding either later can't silently widen access
* to the dangerous eval path. Content scripts carry a `tab`; external pages carry a different `id`.
* Accept only same-extension senders whose origin is this extension, so adding a content script
* later can't silently widen access to the dangerous eval path: a content script shares the
* extension `id` but reports the host page's origin, while an extension page reports
* `chrome-extension://<id>`.
*/
const isTrustedExtensionSender = (sender: unknown, runtimeId: string | undefined): boolean => {
if (runtimeId === undefined || typeof sender !== 'object' || sender === null) {
return false;
}

const { id, tab } = sender as { id?: unknown; tab?: unknown };
return id === runtimeId && tab === undefined;
const { id, origin, url } = sender as { id?: unknown; origin?: unknown; url?: unknown };

if (id !== runtimeId) {
return false;
}

const extensionOrigin = `chrome-extension://${runtimeId}`;

return (
origin === extensionOrigin || (typeof url === 'string' && url.startsWith(`${extensionOrigin}/`))
);
};

const handleTabDebuggerRequest = async ({
Expand Down
Loading
Loading