Compare commits

..

No commits in common. "8aca1169492ac9cfcb2a266139430aef862a40d9" and "e1cf2970da0dcf218c245dab3d163bbe6241ab7d" have entirely different histories.

8 changed files with 13 additions and 321 deletions

View File

@ -104,7 +104,7 @@ npm run write:latest
2. 打开 `chrome://extensions` 2. 打开 `chrome://extensions`
3. 打开右上角 `开发者模式` 3. 打开右上角 `开发者模式`
4. 点击 `加载已解压的扩展程序` 4. 点击 `加载已解压的扩展程序`
5. 选择解压后的 `dist/` 文件夹 5. 选择解压后的插件文件夹
安装后请确认扩展 ID 是: 安装后请确认扩展 ID 是:

View File

@ -73,7 +73,7 @@ The pipeline uses the tag as the release version. Recommended format: `0.MMDD.N`
2. Open `chrome://extensions`. 2. Open `chrome://extensions`.
3. Enable developer mode. 3. Enable developer mode.
4. Click `Load unpacked`. 4. Click `Load unpacked`.
5. Select the unzipped `dist/` folder. 5. Select the unzipped folder.
6. Confirm the extension ID is `pkjopdibdnomhogjheclhnknmejccffg`. 6. Confirm the extension ID is `pkjopdibdnomhogjheclhnknmejccffg`.
## Notes ## Notes

View File

@ -1,188 +0,0 @@
# Unified Dist Distribution Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Make first-time install, Git-based install, ZIP-based install, and later updates all use the same unpacked extension directory named `dist/`.
**Architecture:** Standardize the extension output path through one shared build-path helper, then make ZIP packaging wrap that exact `dist/` directory, and finally update all teammate-facing docs to reference only that path. The release pipeline keeps its existing behavior, but the user-facing artifact shape becomes stable and singular.
**Tech Stack:** TypeScript, Node.js ESM scripts, Chrome MV3 extension packaging, Vitest
---
## File Map
- Create: `scripts/build-output-path.mjs`
- Single source of truth for the unpacked extension output path.
- Modify: `scripts/build.mjs`
- Write release builds to `dist/`.
- Modify: `scripts/package-release.mjs`
- Package the shared `dist/` output instead of any alternate directory.
- Modify: `scripts/package-release-archive.mjs`
- Ensure ZIP output preserves a top-level `dist/` folder.
- Modify: `tests/package-release-archive.test.ts`
- Verify ZIP layout unpacks as `dist/...`.
- Create: `tests/build-output-path.test.ts`
- Verify the shared helper resolves `dist/`.
- Modify: `playwright.config.js`
- Load the extension from `dist/`.
- Modify: `e2e-tests/extension-load.spec.js`
- Verify files under `dist/`.
- Modify: `README.md`
- Remove `dist-release` references and describe `dist/` as the only unpacked directory.
- Modify: `docs/internal-extension-distribution.md`
- Align the release flow language with `dist/`.
- Modify: `docs/【给同事】从Git下载使用说明.md`
- Instruct coworkers to load `dist/`.
- Modify: `.gitignore`
- Remove obsolete `dist-release/` ignore entry if no longer needed.
- Delete tracked directory: `dist-release/`
- Remove the confusing second unpacked extension directory from the repo.
### Task 1: Lock the single output path in tests
**Files:**
- Create: `tests/build-output-path.test.ts`
- Modify: `tests/package-release-archive.test.ts`
- [ ] **Step 1: Write the failing helper test**
Create a small test asserting both development and release builds resolve to:
```ts
path.join("/repo", "dist")
```
- [ ] **Step 2: Write the failing ZIP layout assertion**
Update the archive test so it expects:
```ts
"dist/hello.txt"
```
not a flat file list or any alternate top-level folder.
- [ ] **Step 3: Run focused tests**
Run:
```bash
npm test -- tests/build-output-path.test.ts tests/package-release-archive.test.ts
```
Expected: FAIL until the shared path helper and ZIP layout are implemented.
### Task 2: Standardize build and package scripts
**Files:**
- Create: `scripts/build-output-path.mjs`
- Modify: `scripts/build.mjs`
- Modify: `scripts/package-release.mjs`
- Modify: `scripts/package-release-archive.mjs`
- [ ] **Step 1: Implement the shared output-path helper**
Add `resolveExtensionBuildDir(projectRoot, buildTarget)` and return `dist/` for both release and development flows.
- [ ] **Step 2: Update the build script**
Replace any hard-coded directory switching logic so the release build writes into `dist/`.
- [ ] **Step 3: Update the package script**
Point ZIP packaging at the same `dist/` directory.
- [ ] **Step 4: Keep ZIP layout stable**
Ensure the archive helper stores files under a top-level `dist/` directory inside the ZIP.
- [ ] **Step 5: Verify**
Run:
```bash
npm test -- tests/build-output-path.test.ts tests/package-release-archive.test.ts
npm run build:release
npm run package:internal
```
Expected: PASS, and the ZIP should unpack as `dist/...`.
### Task 3: Remove `dist-release` from tooling and docs
**Files:**
- Modify: `playwright.config.js`
- Modify: `e2e-tests/extension-load.spec.js`
- Modify: `README.md`
- Modify: `docs/internal-extension-distribution.md`
- Modify: `docs/【给同事】从Git下载使用说明.md`
- Modify: `.gitignore`
- Delete tracked directory: `dist-release/`
- [ ] **Step 1: Update tool references**
Point Playwright and debug paths at `dist/`.
- [ ] **Step 2: Update teammate docs**
Make every install/update instruction reference only `dist/`.
- [ ] **Step 3: Remove the obsolete tracked directory**
Delete the committed `dist-release/` tree so future contributors cannot mistake it for the live extension directory.
- [ ] **Step 4: Verify references**
Run:
```bash
rg -n "dist-release" README.md docs package.json scripts e2e-tests playwright.config.js src tests .gitignore
```
Expected: no remaining user-facing `dist-release` references.
### Task 4: Final verification
**Files:**
- Modify any of the above only if fixes are required
- [ ] **Step 1: Run targeted tests**
Run:
```bash
npm test -- tests/build-output-path.test.ts tests/package-release-archive.test.ts tests/manifest.test.ts
```
Expected: PASS.
- [ ] **Step 2: Rebuild and inspect the artifact**
Run:
```bash
npm run build:release
npm run package:internal
unzip -l release/star-chart-search-enhancer-internal.zip | sed -n '1,20p'
```
Expected: the archive contents start with `dist/...`.
- [ ] **Step 3: Full verification**
Run:
```bash
npm test
```
Expected: PASS, or if unrelated pre-existing failures remain, capture them explicitly before completion.
- [ ] **Step 4: Commit**
```bash
git add scripts/build-output-path.mjs scripts/build.mjs scripts/package-release.mjs scripts/package-release-archive.mjs tests/build-output-path.test.ts tests/package-release-archive.test.ts README.md docs/internal-extension-distribution.md docs/【给同事】从Git下载使用说明.md playwright.config.js e2e-tests/extension-load.spec.js .gitignore
git commit -m "chore: unify extension distribution around dist"
```

View File

@ -1,122 +0,0 @@
# Unified Dist Distribution Design
## Goal
Make first-time installation and later updates use the exact same extension directory structure so coworkers never need to learn different paths or loading rules.
## Confirmed Direction
- The only user-facing unpacked extension directory should be `dist/`.
- First install and later update must produce the same directory name and shape.
- Coworkers should always load the same directory in `chrome://extensions`.
## Problem
The current delivery flow has created multiple mental models:
- sometimes coworkers are told to load `dist-release/`
- sometimes the ZIP extracts to a differently named top-level folder
- sometimes Git-based installation and ZIP-based installation do not look identical
This is not user-friendly and increases support cost.
## Scope
This change standardizes the user-facing extension directory across:
- local release builds
- ZIP packaging
- Git-based teammate installation
- later update downloads
- installation and update documentation
This change does not alter:
- extension runtime behavior
- update-check logic itself
- popup auth flow
- COS manifest format
## Distribution Rule
There must be exactly one user-facing extension directory:
- `dist/`
This rule must hold in all paths:
1. Git install
- teammate runs the release build
- resulting unpacked extension directory is `dist/`
2. ZIP install
- teammate unzips the package
- resulting top-level extension directory is `dist/`
3. ZIP update
- teammate downloads the newer ZIP
- unzip result is also `dist/`
- teammate replaces the previous `dist/`
## Packaging Rule
The release ZIP should unpack into a single top-level folder named `dist/`.
Expected unpack result:
- `dist/manifest.json`
- `dist/background/`
- `dist/content/`
- `dist/popup/`
- `dist/assets/`
The ZIP must not unpack as:
- a flat file list
- `dist-release/`
- `star-chart-search-enhancer-internal/`
- any other user-facing top-level folder name
## Build Rule
Release builds should write the unpacked extension directly to `dist/`.
There should not be a second extension build directory that teammates might mistake as the correct one.
If internal scripts need a concept of “release build,” that should be represented by:
- environment/config
- release manifest values
- packaging flow
but not by exposing a second unpacked directory name to users.
## Documentation Rule
All teammate-facing docs must say the same thing:
- first install: load `dist/`
- later update: replace `dist/` and reload
No user-facing doc should mention `dist-release/`.
## CI / Release Rule
Drone and local release scripts must publish only one ZIP layout:
- unzip result is `dist/`
The release flow must not generate a user ZIP whose folder layout differs from the Git-based install path.
## Acceptance Criteria
- `npm run build:release` writes the unpacked extension to `dist/`
- release ZIP unpacks into a top-level `dist/` folder
- first install and later update ZIPs unpack to the same structure
- coworker docs consistently reference `dist/`
- repository no longer contains a second tracked unpacked extension directory that conflicts with `dist/`
## Out of Scope
- changing extension features
- changing the update notification UX
- switching away from unpacked-extension installation
- Chrome Web Store or enterprise force-install deployment

View File

@ -18,9 +18,9 @@
1. 在桌面上找到这个压缩包 1. 在桌面上找到这个压缩包
2. **右键** → 选择"解压到当前文件夹"(或"Extract Here" 2. **右键** → 选择"解压到当前文件夹"(或"Extract Here"
3. 会多出一个文件夹,名字`dist` 3. 会多出一个文件夹,名字类似 `star-chart-search-enhancer-internal`
⚠️ **重要**:这个 `dist` 文件夹要一直放在桌面,不要删、不要改名 ⚠️ **重要**:这个文件夹要一直放在桌面,不要删、不要改名
--- ---
@ -37,9 +37,9 @@
4. 点击左上角出现的 **"加载已解压的扩展程序"** 4. 点击左上角出现的 **"加载已解压的扩展程序"**
5. 选择刚才解压出来的 `dist` 文件夹 5. 选择刚才解压出来的插件文件夹
⚠️ **重要**:如果 `dist` 文件夹里能看到 `manifest.json``content``background``popup` 这些文件和文件夹,说明选对了。 ⚠️ **重要**:如果文件夹里能看到 `manifest.json``content``background``popup` 这些文件和文件夹,说明选对了。
6. 看到绿色的插件卡片出现,就装好了! 6. 看到绿色的插件卡片出现,就装好了!
@ -122,7 +122,7 @@ https://xingtu.cn/ad/creator/market
- 解压下载到的新版本 zip - 解压下载到的新版本 zip
- 打开 `chrome://extensions` - 打开 `chrome://extensions`
- 找到 `Star Chart Search Enhancer` - 找到 `Star Chart Search Enhancer`
- 点击 **"重新加载"**,或重新选择解压后的 `dist` 文件夹 - 点击 **"重新加载"**,或重新选择解压后的新插件文件夹
--- ---
@ -138,7 +138,7 @@ https://xingtu.cn/ad/creator/market
⚠️ **如果重新加载后还是旧版本** ⚠️ **如果重新加载后还是旧版本**
- 先点击插件卡片的 **"移除"** 删除旧版本 - 先点击插件卡片的 **"移除"** 删除旧版本
- 然后重新点击 **"加载已解压的扩展程序"** - 然后重新点击 **"加载已解压的扩展程序"**
- 再次选择新解压出来的 `dist` 文件夹 - 再次选择新解压出来的插件文件夹
--- ---

View File

@ -6,7 +6,7 @@ import yazl from "yazl";
export async function createReleaseArchive({ export async function createReleaseArchive({
archivePath, archivePath,
rootDirName = "dist", rootDirName = "star-chart-search-enhancer-internal",
sourceDir sourceDir
}) { }) {
const zip = new yazl.ZipFile(); const zip = new yazl.ZipFile();

View File

@ -6,7 +6,7 @@ import { describe, expect, test } from "vitest";
import { createReleaseArchive } from "../scripts/package-release-archive.mjs"; import { createReleaseArchive } from "../scripts/package-release-archive.mjs";
describe("package-release-archive", () => { describe("package-release-archive", () => {
test("creates a zip archive with a top-level dist folder", async () => { test("creates a zip archive with a top-level release folder", async () => {
const tempDir = await mkdtemp(path.join(os.tmpdir(), "release-archive-")); const tempDir = await mkdtemp(path.join(os.tmpdir(), "release-archive-"));
const sourceDir = path.join(tempDir, "source"); const sourceDir = path.join(tempDir, "source");
const archivePath = path.join(tempDir, "archive.zip"); const archivePath = path.join(tempDir, "archive.zip");
@ -21,6 +21,8 @@ describe("package-release-archive", () => {
const archive = await readFile(archivePath); const archive = await readFile(archivePath);
expect(archive.byteLength).toBeGreaterThan(0); expect(archive.byteLength).toBeGreaterThan(0);
expect(archive.toString("utf8")).toContain("dist/hello.txt"); expect(archive.toString("utf8")).toContain(
"star-chart-search-enhancer-internal/hello.txt"
);
}); });
}); });