|
1 | | -# HyperChat Codex Workflow (MV3 Main) |
| 1 | +# HyperChat Codex Workflow |
2 | 2 |
|
3 | 3 | ## Branch Discipline |
4 | 4 |
|
5 | | -- Make code changes on `mv2` first. |
6 | | -- `main` is the real MV3 branch. |
7 | | -- `mv3` and `mv3-ltl` are retired. Do not use them as MV3 source branches for new work or cross-repo sync; `main` is the MV3 line LiveTL consumes. |
8 | | -- Do not implement feature/fix work directly on `main`. |
9 | | -- If a task starts on another branch, switch to `mv2` before editing unless the user explicitly asks otherwise. |
| 5 | +- `main` is the only maintained source branch. Make code changes there. |
| 6 | +- `mv3` and `mv3-ltl` are retired. The remote `mv2` branch is a temporary rollback reference until LiveTL migration and runtime validation finish; do not use it for new work or delete it early. |
| 7 | +- There is no branch ladder any more. MV2 and MV3 are **build targets on `main`**, not branches — see "Manifest Version Targets" below. |
10 | 8 | - If a task touches both HyperChat and LiveTL, HyperChat still goes first. |
11 | 9 | - Cross-repo order is mandatory: |
12 | | - 1. HyperChat `mv2` |
13 | | - 2. HyperChat `main` |
14 | | - 3. LiveTL `develop` |
15 | | - 4. LiveTL `mv3-fr` |
16 | | - 5. LiveTL `release` |
| 10 | + 1. HyperChat `main` |
| 11 | + 2. LiveTL `develop` |
| 12 | + 3. LiveTL `mv3-fr` |
| 13 | + 4. LiveTL `release` |
17 | 14 | - Never start cross-repo work in LiveTL when the HyperChat submodule also needs to change. |
18 | 15 | - If the task also requires syncing YtcFilter (YTCF), do it after HyperChat `main` is updated: |
19 | 16 | - merge HyperChat `main` into YTCF `master` |
|
28 | 25 | - `order matters` |
29 | 26 | - Avoid padded scopes, issue-number prefixes, and changelog-style essays in commit subjects. |
30 | 27 | - A slightly dry or funny commit is fine if it is still clear at a glance. |
31 | | -- Prefer proper merges when carrying `mv2` work into `main`. |
32 | | -- If MV3 needs follow-up adaptation, keep that as a small, explicit commit after the merge instead of rewriting history or hand-copying changes. |
| 28 | + |
| 29 | +## Manifest Version Targets |
| 30 | + |
| 31 | +- `main` builds three targets: `chrome` (MV3), `firefox` (MV3), and `mv2` (MV2, Firefox-only). |
| 32 | +- The `mv2` target is **not** legacy cruft. Firefox's MV3 support is unreliable for LiveTL's needs, so LiveTL's Firefox variant will consume it after the downstream migration. Do not "simplify" it away. |
| 33 | +- Keep the MV2/MV3 distinction in exactly two places: |
| 34 | + - `src/manifest.json` — `{{mv2}}.` / `{{mv3}}.` key prefixes, resolved by `scripts/resolve-manifest.ts`. The MV tag must come **first** in nested keys (`{{mv3}}.{{firefox}}.background`); the reverse order leaks a literal tag into the built manifest. |
| 35 | + - `__MV__` in source — a build-time constant, so unused branches are dropped per target. |
| 36 | +- Do not add per-MV source files (`chat-background.mv2.ts` and friends). `main`'s architecture — thin background plus the broker in `src/ts/messaging.ts` — runs under MV2 as-is. Port MV3 patterns down to MV2, never MV2's persistent-background design up. |
| 37 | +- Prefer shared, untagged config. Only tag a key when MV2 and MV3 genuinely differ. |
| 38 | +- Only the two MV3 zips are released. `mv2` is built in CI for breakage coverage and consumed by LiveTL via submodule. |
| 39 | + |
| 40 | +## Build-Time Constants (submodule consumers) |
| 41 | + |
| 42 | +`src/` depends on three bare globals, declared in `src/ts/typings/vite-env.d.ts` |
| 43 | +and supplied by `vite.config.ts` for our own builds: |
| 44 | + |
| 45 | +| Constant | Emitted literal | Meaning | |
| 46 | +| --- | --- | --- | |
| 47 | +| `__BROWSER__` | string — `"chrome"` / `"firefox"` | target browser | |
| 48 | +| `__VERSION__` | string — `"3.3.0"` | version written into the manifest | |
| 49 | +| `__MV__` | **number** — `2` / `3` | target manifest version | |
| 50 | + |
| 51 | +`__MV__` is compared with strict equality (`__MV__ === 2`), so it must emit a |
| 52 | +**number literal**. Defining it as the string `"2"` makes every check silently |
| 53 | +false and the MV2 build takes MV3 code paths — no error, just wrong behavior. |
| 54 | + |
| 55 | +Both bundlers do textual substitution, so the value is source text, not a JS |
| 56 | +value. `JSON.stringify()` is the safe spelling in both: |
| 57 | + |
| 58 | +```js |
| 59 | +// vite |
| 60 | +define: { __BROWSER__: JSON.stringify(browser), __MV__: JSON.stringify(2) } |
| 61 | + |
| 62 | +// webpack — values are code fragments, so a bare string is an identifier: |
| 63 | +// __BROWSER__: 'firefox' -> emits `firefox` -> ReferenceError |
| 64 | +new webpack.DefinePlugin({ __BROWSER__: JSON.stringify('firefox'), __MV__: 2 }) |
| 65 | +``` |
| 66 | + |
| 67 | +**Anything that compiles this source with its own bundler must define all three**, |
| 68 | +or the bundle ships a reference to an undefined global and throws at runtime. |
| 69 | +LiveTL is the one such consumer: it builds `chat-background.ts`, |
| 70 | +`chat-injector.ts`, `chat-interceptor.ts`, `hyperchat.ts` and `options.ts` as its |
| 71 | +own entry points, so it needs these in **both** its webpack (MV2) and vite (MV3) |
| 72 | +configs. `__MV__` must match that consumer's own manifest version, not ours. |
| 73 | + |
| 74 | +Used by `WelcomeMessage.svelte`, `Hyperchat.svelte`, `HyperchatButton.svelte`, |
| 75 | +`chat-background.ts`, `chat-injector.ts`. When adding a new constant, update this |
| 76 | +table — a missing define fails at runtime, not at build time. |
33 | 77 |
|
34 | 78 | ## Code Patterns |
35 | 79 |
|
36 | 80 | - Prefer editing existing modules and utilities over creating one-off files for tiny helpers. |
37 | 81 | - If a helper obviously belongs in an existing shared utility file, put it there. |
38 | | -- Put shared behavior on `mv2` first; `main` should usually be a merge-plus-adaptation branch, not a separate feature branch. |
39 | | -- Keep MV3 adaptation narrow: |
40 | | - - preserve branch-specific build/runtime wiring |
| 82 | +- Keep MV2 adaptation narrow: |
41 | 83 | - change only what is required for manifest/background/injection differences |
| 84 | + - reach for `__MV__` only when an API genuinely differs between manifest versions |
42 | 85 | - Prefer render-edge formatting over mutating raw identity data: |
43 | 86 | - keep parsed message/channel ids untouched |
44 | 87 | - transform display text at component or view-model boundaries |
|
61 | 104 | - name: `chrome-devtools` |
62 | 105 | - command: `npx -y chrome-devtools-mcp@latest --browserUrl=http://127.0.0.1:9222` |
63 | 106 | - Use `scripts/codex-dev.sh watch` once per session to keep Chrome extension builds live in the background. |
64 | | -- On `main`, this resolves to MV3 scripts (`dev:chrome`/`build:chrome`) and `build/chrome` output automatically. |
65 | | -- On `mv2`, watcher mode prefers `npm run start:none` so build watch stays alive without separate browser autolaunch. |
| 107 | +- The watcher resolves to MV3 Chrome scripts (`dev:chrome`/`build:chrome`) and `build/chrome` output automatically. |
| 108 | +- The harness is Chromium-only. The MV2 target is Firefox-only, so `go-test` does not cover it — validate MV2 by loading `build/mv2` in Firefox by hand. |
66 | 109 | - Start headless browser testing only when explicitly requested (for example: "go test", "test this", "run browser test"). |
67 | 110 | - For test runs, use `scripts/codex-dev.sh go-test`. This guarantees: |
68 | 111 | - MCP configuration is present |
|
0 commit comments