Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
32 changes: 0 additions & 32 deletions .beads/.gitignore

This file was deleted.

81 changes: 0 additions & 81 deletions .beads/README.md

This file was deleted.

62 changes: 0 additions & 62 deletions .beads/config.yaml

This file was deleted.

15 changes: 0 additions & 15 deletions .beads/issues.jsonl

This file was deleted.

4 changes: 0 additions & 4 deletions .beads/metadata.json

This file was deleted.

39 changes: 1 addition & 38 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,3 @@
# Agent Instructions

This project uses **bd** (beads) for issue tracking. Run `bd onboard` to get started.

## Quick Reference

```bash
bd ready # Find available work
bd show <id> # View issue details
bd update <id> --status in_progress # Claim work
bd close <id> # Complete work
bd sync # Sync with git
```

## Landing the Plane (Session Completion)

**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds.

**MANDATORY WORKFLOW:**

1. **File issues for remaining work** - Create issues for anything that needs follow-up
2. **Run quality gates** (if code changed) - Tests, linters, builds
3. **Update issue status** - Close finished work, update in-progress items
4. **PUSH TO REMOTE** - This is MANDATORY:
```bash
git pull --rebase
bd sync
git push
git status # MUST show "up to date with origin"
```
5. **Clean up** - Clear stashes, prune remote branches
6. **Verify** - All changes committed AND pushed
7. **Hand off** - Provide context for next session

**CRITICAL RULES:**
- Work is NOT complete until `git push` succeeds
- NEVER stop before pushing - that leaves work stranded locally
- NEVER say "ready to push when you are" - YOU must push
- If push fails, resolve and retry until it succeeds

No issue tracker configured.
4 changes: 2 additions & 2 deletions extension/manifest.chrome.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "LightSession Pro for ChatGPT",
"version": "1.6.2",
"version": "1.6.3",
"description": "Keep ChatGPT fast by keeping only the last N messages in the DOM. Local-only.",
"icons": {
"16": "icons/icon-16.png",
Expand All @@ -13,7 +13,7 @@
"default_title": "LightSession Pro",
"default_popup": "popup/popup.html"
},
"permissions": ["storage", "tabs"],
"permissions": ["storage", "tabs", "declarativeContent"],
"host_permissions": [
"*://chat.openai.com/*",
"*://chatgpt.com/*"
Expand Down
2 changes: 1 addition & 1 deletion extension/manifest.firefox.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "LightSession Pro for ChatGPT",
"version": "1.6.2",
"version": "1.6.3",
"description": "Keep ChatGPT fast by keeping only the last N messages in the DOM. Local-only.",
"icons": {
"16": "icons/icon-16.png",
Expand Down
105 changes: 105 additions & 0 deletions extension/src/background/action-state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/**
* LightSession Pro - Action icon state
* Enable the action only on ChatGPT sites.
*/

import browser from '../shared/browser-polyfill';
import { isChatGptUrl } from '../shared/url';

const DEFAULT_POPUP = browser.runtime.getManifest().action?.default_popup ?? 'popup/popup.html';
const CHATGPT_RULES = [
{ hostEquals: 'chatgpt.com' },
{ hostEquals: 'chat.openai.com' },
];

function setPopupForTab(tabId: number, popup: string): void {
if (!browser.action) {
return;
}

try {
void browser.action.setPopup({ tabId, popup });
} catch {
// Ignore action update failures (e.g., restricted tabs)
}
}

export function updateActionForTab(tabId: number, url?: string | null): void {
if (!browser.action || !tabId) {
return;
}

try {
if (isChatGptUrl(url)) {
void browser.action.enable(tabId);
setPopupForTab(tabId, DEFAULT_POPUP);
} else {
void browser.action.disable(tabId);
setPopupForTab(tabId, '');
}
} catch {
// Ignore action update failures (e.g., restricted tabs)
}
}

export function disableActionByDefault(): void {
if (!browser.action) {
return;
}

try {
void browser.action.disable();
void browser.action.setPopup({ popup: '' });
} catch {
// Ignore failures for restricted contexts
}
}

export async function ensureDeclarativeActionRules(): Promise<void> {
const declarative = (
browser as unknown as { declarativeContent?: typeof chrome.declarativeContent }
).declarativeContent;

if (!declarative?.onPageChanged || !declarative.PageStateMatcher || !declarative.ShowAction) {
return;
}

const rules = [
{
conditions: CHATGPT_RULES.map(
(rule) => new declarative.PageStateMatcher({ pageUrl: rule })
),
actions: [new declarative.ShowAction()],
},
];

await new Promise<void>((resolve) => {
declarative.onPageChanged.removeRules(undefined, () => resolve());
});

declarative.onPageChanged.addRules(rules);
}

export async function syncActionStateForAllTabs(): Promise<void> {
if (!browser.action) {
return;
}

try {
const tabs = await browser.tabs.query({});
for (const tab of tabs) {
if (!tab?.id) continue;
updateActionForTab(tab.id, tab.url);
}
} catch {
try {
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
for (const tab of tabs) {
if (!tab?.id) continue;
updateActionForTab(tab.id, tab.url);
}
} catch {
// Ignore tab query failures
}
}
}
Loading