{"owner":"gaozhangmin","repo":"aliyunpan","hasSkills":true,"totalSkillsCount":3,"totalTokensCount":8257,"categories":["anthropic-skill","claude-rule","root-instruction"],"hasMcp":false,"mcpConfig":null,"found":["clouddrive-cli/skill/SKILL.md","CLAUDE.md","AGENTS.md"],"skills":{"clouddrive-cli/skill/SKILL.md":"---\nname: clouddrive-cli\ndescription: Use when an agent needs to operate cloud-drive accounts through clouddrive-cli or clouddrive-mcp: discover logged-in accounts, inspect/list/walk/search cloud files, read local documents as context, generate or apply safe media rename/move/trash/upload/organize plans, and roll back supported operations.\nallowed-tools:\n  - Bash(clouddrive-cli:*)\n  - Bash(clouddrive-mcp:*)\n  - Read\n---\n\n# clouddrive-cli\n\n`clouddrive-cli` turns BoxPlayer cloud-drive accounts into a deterministic command surface for humans and AI agents. It supports Aliyun Drive, OneDrive, Dropbox, Box, 123Pan, 115 Drive, Baidu Netdisk, and PikPak.\n\nThis skill is the orientation layer. Discover the live CLI surface first, then choose the smallest safe command path for the user's goal.\n\n## The three pillars\n\n- **Account and provider discovery** — `auth list`, `settings show`, and `providers capabilities` tell you which accounts exist and which operations each provider supports.\n- **Cloud file operations** — `files list|walk|tree|stats|info|download|search|mkdir|rename-apply|move-apply|trash-apply` provide the stable boundary for reading and changing cloud files.\n- **Agent workflows** — `docs read`, `media *`, `upload *`, `organize *`, and `ops *` let agents combine local instructions, cloud inventory, dry-run plans, execution, and rollback.\n\n## Install and locate\n\n```bash\nwhich clouddrive-cli\nclouddrive-cli --help\nclouddrive-cli list --format json\n```\n\nIf the command is missing, ask the user to install it from BoxPlayer account settings or with `npm install -g clouddrive-cli`.\n\nThere are two install modes:\n\n- **BoxPlayer app mode** — the Electron app registers `clouddrive-cli` and exports logged-in account tokens.\n- **Standalone CLI mode** — install with npm and use `auth login` or `auth import-token` to add accounts.\n\n## Discover first\n\nDo not treat this file as the complete command registry. Start with live discovery:\n\n```bash\nclouddrive-cli list --format json\nclouddrive-cli schema commands\nclouddrive-cli auth list --format json\nclouddrive-cli settings show --format json\nclouddrive-cli providers capabilities --format json\n```\n\n`clouddrive-cli list --format json` is the source of truth for command metadata such as `access`, `requiresDryRun`, `destructive`, and `undoable`. `providers capabilities` is the source of truth for provider-specific support such as search, mkdir, move, rename, trash/delete, upload, recursive walk, path addressing, and file-id addressing.\n\n## Universal conventions\n\n| convention | meaning |\n|------------|---------|\n| `--format json` / `--json` | Agent-friendly JSON output. Prefer this by default. |\n| JSON errors | Failures return `{ ok: false, error: { code, message, exitCode } }` in JSON mode. Branch on `error.code`, not message text. |\n| dry-run first | Commands marked `requiresDryRun` must be previewed before execution. |\n| capability check | Before mkdir, move, rename, trash, upload, or organize apply, check `providers capabilities`. |\n| large output | Commands with `largeOutput: true` should use `--output <file.json>` so stdout stays a compact summary. |\n| rationale | Write commands accept `--rationale <reason>`; use it to preserve why the Agent is acting. |\n| no invented IDs | Get file IDs from `files list`, `files walk`, `files search`, `files tree`, or `files info`. |\n\nCommon error codes:\n\n| code | meaning | response |\n|------|---------|----------|\n| `AUTH_ERROR` | Missing/expired account or login failure. | Run `auth list`, `auth check`, `auth login`, or ask for token import. |\n| `PROVIDER_API_ERROR` | Provider returned an API/HTTP error. | Retry only if transient; otherwise record provider limitation. |\n| `UNSUPPORTED_CAPABILITY` | Provider or command capability is unavailable. | Stop or choose a supported fallback. |\n| `VALIDATION_ERROR` | Bad args, missing files, invalid plan, unknown operation. | Fix input before retrying. |\n\n## Read workflows\n\nUse bounded reads before large traversals:\n\n```bash\nclouddrive-cli files stats --provider aliyun --account default --file-id root --depth 2 --format json\nclouddrive-cli files stats --provider aliyun --account default --file-id root --output stats.json --format json\nclouddrive-cli files tree --provider aliyun --account default --file-id root --depth 1\nclouddrive-cli files list --provider aliyun --account default --file-id root --format json\nclouddrive-cli files list --provider aliyun --account default --file-id root --limit 100 --format json\nclouddrive-cli files list --provider aliyun --account default --file-id root --limit 100 --cursor <nextCursor> --format json\nclouddrive-cli files download --provider aliyun --account default --file-id <file-id> --output ./download.bin --format json\nclouddrive-cli files search --provider aliyun --account default --name \"movie\" --limit 50 --format json\n```\n\nRules of thumb:\n\n- Use `stats` or shallow `tree` to understand scale.\n- Use `search` for known keywords.\n- Use `walk` only after narrowing scope or when a full inventory is explicitly needed.\n- Avoid raw `files tree --json` and broad `walk` on large roots unless you will save and summarize the output locally.\n\nProvider root defaults when `--file-id` is omitted:\n\n| provider | default root |\n|----------|--------------|\n| aliyun | `root` |\n| cloud123 | `0` |\n| 115 | `0` |\n| baidu | `/` |\n| pikpak | `*` |\n| dropbox | empty string |\n| onedrive | `onedrive_root` |\n| box | `box_root` |\n\n## Write workflows\n\nNever apply a write plan first. The safe sequence is:\n\n1. Discover command metadata with `clouddrive-cli list --format json`.\n2. Check provider capability with `clouddrive-cli providers capabilities --format json`.\n3. Generate or read a plan.\n4. Run the dry-run or preview command.\n5. Show the user a concise summary of planned changes.\n6. Execute only after explicit user approval.\n7. Record the operation ID and rollback path when available.\n\nInclude `--rationale` on write commands, for example:\n\n```bash\nclouddrive-cli upload apply upload-plan.json --dry-run --rationale \"User asked to back up this folder\" --format json\n```\n\nCommon write previews:\n\n```bash\nclouddrive-cli files rename-apply rename-plan.json --current files.json --dry-run --format json\nclouddrive-cli files move-apply move-plan.json --dry-run --format json\nclouddrive-cli files trash-apply trash-plan.json --format json\nclouddrive-cli upload apply upload-plan.json --dry-run --format json\nclouddrive-cli organize apply organize-plan.json --dry-run --summary --format json\n```\n\nNotes:\n\n- `trash-apply` defaults to preview; execution requires `--apply`.\n- Rename and move operations are undoable through `ops undo`; trash is not.\n- Dropbox and Baidu move/trash plans may require path fields in addition to file IDs.\n- Upload planning exists for all providers. Real byte upload is wired for providers whose `providers capabilities` entry has `uploadFile: true` (`aliyun`, `cloud123`, `115`, `baidu`, `dropbox`, `onedrive`, `box` in this build); `pikpak` remains plan/dry-run only.\n\n## Media organization\n\nRecommended flow:\n\n```bash\nclouddrive-cli docs read ./rules.md --max-chars 50000 --format json\nclouddrive-cli docs read ./rules.pdf --pdf-format markdown --pdf-pages 1-3 --format json\nclouddrive-cli docs convert ./pdf-folder --output ./out --pdf-format json,html,pdf,markdown,tagged-pdf,text --format json\nclouddrive-cli files stats --provider aliyun --account default --file-id <folder-id> --depth 2 --format json\nclouddrive-cli files walk --provider aliyun --account default --file-id <folder-id> --output files.json --format json\nclouddrive-cli media match --input files.json --format json\n# Generate rename-plan.json yourself from rules, inventory, and match output.\nclouddrive-cli files rename-apply rename-plan.json --dry-run --format json\n```\n\n`media match` returns media fields under `match`, for example `{ fileId, name, match: { type, title, year, season, episode, confidence, jellyfin_name } }`.\n\nFor full-drive organization, treat broad plans as risky even if dry-run succeeds. Sample suspicious moves, check whether existing meaningful folders would be flattened into generic `Movies` or `TV Shows`, and prefer applying one folder/category at a time.\n\n## Rollback\n\n```bash\nclouddrive-cli ops list --format json\nclouddrive-cli ops show <operation-id> --format json\nclouddrive-cli ops undo <operation-id> --dry-run --format json\nclouddrive-cli ops undo <operation-id> --format json\n```\n\nAlways run `ops undo --dry-run` first. Only rename and move operations have CLI undo.\n\n## MCP\n\n`clouddrive-mcp` exposes the CLI manifest as MCP tools. Tool names and input schemas are generated from the same command manifest used by `clouddrive-cli list --format json`, so CLI/MCP discovery should stay aligned. Prefer direct CLI commands when:\n\n- You need file output redirection or plan files.\n- You are testing CLI behavior during skill/CLI iteration.\n\n## Known provider limitations\n\n- OneDrive `files search` may intermittently fail with Microsoft Graph `generalException` / HTTP 500. Use `files walk` plus local filtering as fallback.\n- PikPak `files search --name` may ignore the name query and return root items. Use `files walk` plus local filtering.\n- Baidu `files info` handles `filemetas` under either `list` or `info`, but `errno=12` can still indicate an API/token limitation. Fall back to `files walk` or `files search`.\n- 115 Open API folder fields may map folders as `type: file`. Confirm folder-ness by trying `files list --file-id <fileId>` before planning folder operations.\n\n## Don't\n\n- Don't paste this skill's command list into a plan; call `clouddrive-cli list --format json`.\n- Don't run non-dry-run writes without explicit user approval.\n- Don't assume root path tokens are portable across providers.\n- Don't continue after a structured JSON error without branching on `error.code`.\n- Don't emit huge raw inventories to the user; save, summarize, and sample.\n","CLAUDE.md":"# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Quick commands\n\n```bash\npnpm install          # pnpm only — never npm/yarn\npnpm dev              # hot-reload Electron dev server (Vite + vue-tsc)\npnpm run build        # version bump → typecheck → vite bundle\npnpm run build:electron  # full build + electron-builder packaging\npnpm run test         # focused Vitest suite (Node env, aria2 + motrix + utils)\npnpm run test:clouddrive-cli  # clouddrive-cli tests only\npnpm run build:mac    # unsigned macOS .dmg/.zip\npnpm run build:mac:signed  # signed + notarized macOS\npnpm run build:linux  # Linux .deb/.AppImage/.pacman\npnpm run build:windows  # Windows .exe/.zip\npnpm run build:all    # cross-platform sequentially\npnpm run config:clean     # blank API keys in src/config.ts (pre-commit hook)\npnpm run config:restore   # restore real keys after commit\n```\n\n## Architecture (Electron + Vue 3 + Vite)\n\n```\nelectron/main/       Electron main process (entry: electron/main/index.ts)\n  core/              Window lifecycle, IPC, auto-update, protocol, dialogs\n  aria/              Aria2c download engine (config, UPnP, runtime)\nelectron/preload/    Preload scripts (IPC bridge)\n\nsrc/                 Vue 3 renderer\n  aliapi/            Alibaba Cloud Drive SDK (files, share, user, etc.)\n  cloudbaidu/        Baidu Netdisk provider\n  cloud123/          123Pan provider\n  cloud115/          115Pan provider\n  pikpak/            PikPak provider\n  onedrive/          OneDrive provider\n  dropbox/           Dropbox provider\n  box/               Box provider\n  quark/             Quark provider\n  cloud139/          CMCloud provider\n  cloud189/          Tianyi Cloud provider\n  pan/               File manager UI (tree, menus, dialogs)\n  media-server/      Jellyfin/Emby/Plex integration\n  down/              Download manager + Aria2 integration\n  layout/            Main layout views (PageVideo, PageMusic, etc.)\n  module/            Feature modules (audioplayer, musicsdk, lyricplayer, theme)\n  store/             Pinia stores\n  components/        Shared Vue components\n  utils/             Shared utilities\n  user/              Auth, account management UI\n\nshared/              Code shared between main + renderer (constants, config keys, UA)\nscripts/             Build scripts, CLI entry points (clouddrive-cli.mjs, clouddrive-mcp.mjs)\nclouddrive-cli/      Standalone CLI + MCP server package (npm: clouddrive-cli)\n  core/              Command implementations, MCP server, upload planning\n  providers/         8 cloud-drive provider implementations\n  media/             Media matching + rename logic\n```\n\nPath aliases: `@shared/*` → `shared/*`, `@main/*` → `electron/main/*`\n\n## Key patterns\n\n- **pnpm only** — lockfile is `pnpm-lock.yaml`; `package-lock.json`/`yarn.lock` are gitignored\n- **Node ≥ 18**\n- **Pre-commit hooks** (`nano-staged.mjs`): prettier + eslint on JS/TS, stylelint + prettier on Vue/CSS, typecheck on changed `src/` files\n- **Formatting**: single quotes, no semicolons, 260 printWidth, no trailing commas, LF, `sortAttributes: true` in Vue\n- **TypeScript**: strict mode, ESNext target, node moduleResolution\n- **Sensitive config**: `scripts/clean-config.js` blanks API keys pre-commit; restore with `pnpm run config:restore`\n- **Vitest**: Node environment only, explicit test directory list in `vitest.config.ts` (not glob patterns). Add new test dirs to config.\n- **CI**: Manual trigger only via `.github/workflows/release.yml`, publishes draft GitHub Release\n\n## clouddrive-cli (AI agent integration)\n\nStandalone CLI + MCP server for agent-driven cloud-drive operations. Supports 8 providers: aliyun, cloud123, 115, baidu, pikpak, onedrive, box, dropbox.\n\nKey bins: `clouddrive-cli` (CLI), `clouddrive-mcp` (MCP server). Both point to `scripts/clouddrive-cli.mjs` and `scripts/clouddrive-mcp.mjs` respectively.\n\nAgent rules when using the CLI:\n1. Discover commands first: `clouddrive-cli list --format json`\n2. Check capabilities: `clouddrive-cli providers capabilities --format json`\n3. Always dry-run before destructive ops\n4. Never invent file IDs — they must come from `files list`/`walk`/`search`/`tree`\n5. Use `--output <file.json>` for large results\n\n## Adding a new cloud-drive provider\n\nFollow the 15-step checklist in `AGENT.md` (OAuth → provider detection → file listing → download/playback → search → thumbnails → file operations → sharing → upload → media scan → folder picker → menu boundaries → properties/recycle bin → tests → verification). The checklist is authoritative — do not ship a provider that only does file listing.\n","AGENTS.md":"# AGENTS.md — BoxPlayer (aliyunpan)\n\n## “All Platforms” Scope\n\n- When the user says “all platforms” (`所有平台`), treat it as one request spanning all three repositories: `~/aliyunpan`, `~/BoxPlayer_Android`, and `~/XbyVideoHub`.\n- Implement the Electron/aliyunpan surface in `~/aliyunpan`; implement Android phone, tablet, and Android TV in `~/BoxPlayer_Android`; implement macOS, iOS/iPadOS, and tvOS in `~/XbyVideoHub`.\n- Inspect and modify each repository independently. Do not assume a change in one repository propagates to the other two.\n\n## Quick reference\n\n```bash\npnpm install          # install deps (pnpm only, never npm/yarn)\npnpm dev              # hot-reload Electron dev server\npnpm run build        # typecheck + bundle (vue-tsc --noEmit && vite build)\npnpm run test         # focused Vitest suite (not full repo)\npnpm run test:clouddrive-cli  # clouddrive-cli tests only\n```\n\n## Home Category Context Menus\n\n- Categories and independently placeable subcategories, including series, playlists, movie/TV child categories, genre, rating, score, and release-date values, use the same placement context-menu state machine.\n- An unplaced item shows “Add to Home” and “Add to Favorites”; both actions prompt for a user-defined display name.\n- After either add action succeeds, or when the item is initially visible on Home, the menu immediately switches to “Remove from Home” and “Rename Favorite.” The menu must not allow simultaneous Home and Favorites placement.\n- “Remove from Home” clears whichever placement contains the item. Renaming a favorite changes only its Favorites card title and does not rename the Home or sidebar title.\n\n## Package manager: pnpm only\n\nLockfile is `pnpm-lock.yaml`. `package-lock.json` and `yarn.lock` are in `.gitignore`.\nNever use `npm install` or `yarn`.\n\n## Node version\n\n`engines.node >= 22.12.0` in package.json. Electron 40 requires Node 22.12+ during install/build.\n\n## Build pipeline order matters\n\n`pnpm run build` runs **version bump → typecheck → vite bundle**. The version bump (`version.mjs`) auto-increments the patch version in package.json before every build. The build removes `dist/` and `release/` directories on start.\n\n`pnpm run build:electron` calls `build` first, then runs `electron-builder`.\n\nFor platform-specific packaging:\n```bash\npnpm run build:mac       # unsigned macOS\npnpm run build:mac:signed  # signed + notarized\npnpm run build:linux\npnpm run build:windows\npnpm run build:all       # cross-platform, sequential\n```\n\n## Sensitive config: generated secrets\n\nPrivate client IDs, client secrets, API keys, and private API URLs live outside git:\n\n```bash\npnpm run secrets:generate\n```\n\nLocal development reads them from `.env.local` and generates `src/secrets.generated.ts`. GitHub Actions reads the same keys from GitHub Secrets and runs `scripts/generate-secrets.mjs --mode=ci --strict` before building.\n\n`.env.local` and `src/secrets.generated.ts` are ignored and must never be committed. `src/config.ts` should import generated secrets or use placeholders, not contain real private values.\n\n## Architecture: Electron + Vue 3 + Vite\n\n| Directory | Purpose |\n|---|---|\n| `electron/main/` | Electron main process (entry: `electron/main/index.ts`) |\n| `electron/preload/` | Preload scripts |\n| `src/` | Vue 3 renderer (components, views, stores, API modules) |\n| `shared/` | Code shared between main + renderer |\n| `scripts/` | Build, CLI entry points, config management |\n| `clouddrive-cli/` | Standalone CLI package (published to npm as `clouddrive-cli`) |\n\nPath aliases (set in `tsconfig.json`, `vite.config.ts`, `vitest.config.ts`):\n- `@shared/*` → `shared/*`\n- `@main/*` → `electron/main/*`\n\nCloud provider API modules in `src/`: `aliapi/`, `cloudbaidu/`, `cloud123/`, `cloud115/`, `pikpak/`, `onedrive/`, `box/`, `dropbox/`, `quark/`, `cloud139/`, `cloud189/`.\n\n## GitHub Issue workflow\n\nWhen the user asks to handle GitHub Issues, first fetch the complete list of unfinished/open Issues in the requested repository. Review each Issue individually, identify its likely cause and affected code, and report the triage before changing code. Then implement fixes and run focused regression tests for each applicable Issue. Do not jump straight into a code change based only on the newest Issue or close an Issue before its fix is verified. If the repository or Issue access is unavailable, state that limitation rather than assuming the list is complete.\n\n## Testing: Vitest, Node environment, selective includes\n\n### Default app inspection: attach to the existing dev app\n\n- Unless the user explicitly asks to execute E2E tests, always connect to the app the user already started with `pnpm run dev` for inspection, reproduction, debugging, and UI verification.\n- Use the existing Electron CDP endpoint (normally `http://127.0.0.1:9223`; confirm the active endpoint). Playwright may attach with `chromium.connectOverCDP`; do not use `electron.launch`, spawn another Electron process, or start another `pnpm run dev` instance.\n- Preserve the running app's real user-data directory, accounts, settings, and playback state. Do not substitute an isolated/temporary profile or seed test data into the user's app.\n- Requests to review, investigate, reproduce, fix, or verify a bug are not explicit requests to run E2E tests. Do not automatically run `pretest:e2e`, `test:e2e`, or Playwright specs whose fixtures launch a separate app.\n- If the existing app or relevant window is unavailable, report that and ask the user to start/reopen it. Do not silently launch a replacement. Request approval before restarting the user's dev app when a main-process or native-module change requires it.\n- This rule takes precedence over the E2E workflow below. Record what was actually verified in the existing dev app; do not describe attached-session checks as production E2E acceptance. A pending E2E gate does not authorize launching another app.\n\n### Playwright acceptance gate when E2E execution is explicitly requested\n\nWhen the user explicitly asks to execute E2E tests, verify bug fixes through Playwright against an actually launched Electron application using the workflow below. Unit tests, type checks, source inspection, and merely starting `pnpm run dev` cannot replace this E2E gate.\n\n1. Add or update a Playwright regression test that reproduces the reported failure through the user-visible application flow.\n2. Build the production Electron entry with `pnpm run pretest:e2e`; do not test stale `dist/` output or an installed older BoxPlayer build.\n3. Run the focused Playwright regression test and record the exact command and result.\n4. For cloud-drive bugs, use the configured real account and exercise the real provider API. Do not skip the relevant real-account case or replace it with mocks.\n5. For platform-specific behavior that cannot execute on the current host, run Playwright on the target platform before calling the bug fixed. If that is unavailable, report the fix as unverified/blocked rather than complete.\n6. A failed, skipped, or unexecuted Playwright regression test blocks declaring the bug fixed and blocks release publication.\n\nKeep the regression test after the fix so the same bug cannot silently return.\n\nTests run in Node environment (not jsdom). The `vitest.config.ts` lists explicit test directories — not a glob over `**/*.test.ts`. Tests outside these paths are not picked up:\n\n- `electron/main/core/__tests__/`, `electron/main/aria/__tests__/`\n- `shared/__tests__/`, `scripts/__tests__/`\n- `src/down/motrix-integration/`, `src/media-server/__tests__/`\n- `src/utils/__tests__/`, `src/aliapi/__tests__/`\n- `src/pikpak/__tests__/`, `src/quark/__tests__/`\n- `src/dropbox/__tests__/`, `src/onedrive/__tests__/`, `src/box/__tests__/`\n- `clouddrive-cli/__tests__/`\n\nDefault `pnpm run test` runs only a subset (aria2 tests, motrix integration, a couple utils files).\n\nWhen adding tests in a new directory, update `vitest.config.ts`.\n\n## Pre-commit hooks\n\nDo not rely on pre-commit cleanup for secrets. Secret safety is handled by keeping real values in ignored/generated files and GitHub Secrets.\n\n## Formatting conventions\n\nFrom `.prettierrc`:\n- Single quotes, no semicolons\n- 260 printWidth (very wide)\n- No trailing commas\n- LF line endings\n- `sortAttributes: true` on HTML/Vue\n\n## TypeScript\n\n- `tsconfig.json` targets ESNext, moduleResolution node, strict mode, `@shared/*` and `@main/*` path aliases\n- Includes `src/` and `shared/`, excludes `shared/__tests__`\n- References `tsconfig.node.json` for Electron-side code\n\n## Provider Integration Checklist\n\nWhen adding a new cloud-drive provider, implement the following in order unless the user explicitly excludes a step. Do not stop after only wiring file listing. Sync/change-listening is not required by default.\n\n### 1. Account And Auth\n\n- Read the official OAuth/API documentation and prefer stable API versions.\n- Add `src/<provider>/auth.ts` with auth URL, authorization-code token exchange, and refresh token support.\n- Define `CLIENT_ID` / `CLIENT_SECRET` placeholder constants, defaulting to empty strings.\n- Add app key / secret fields to `.env.example`, `src/secrets.example.ts`, and `scripts/generate-secrets.mjs`.\n- Add the provider to `tokenfrom` in `src/user/userstore.ts`.\n- Wire login, token refresh, and drive loading in `src/user/userdal.ts`.\n- Add login entry points in `src/user/UserLogin.vue` and `src/user/UserInfo.vue`.\n\n### 2. Provider Detection And Drive Model\n\n- Add `is<Provider>User` in `src/aliapi/utils.ts`.\n- Update `GetDriveID` and `GetDriveType`, modeling third-party drives as a single-root drive.\n- Filter unsupported virtual directories in `src/pan/PanLeft.vue` and `src/pan/pantreestore.ts`.\n\n### 3. File List And Detail\n\n- Add `src/<provider>/dirfilelist.ts`.\n- Implement root listing, child directory pagination, and file detail.\n- Map official file models to `IAliGetFileModel`; at minimum fill `drive_id`, `file_id`, `parent_file_id`, `name`, `isDir`, `category`, `icon`, `size`, `time`, `thumbnail`, and `content_hash`.\n- Store provider-specific path, parent id, download URL, or similar metadata in `description`.\n- Wire root loading, directory listing, and search-listing branches in `src/pan/pandal.ts`.\n- Wire provider file detail in `src/aliapi/file.ts` `ApiFileInfo`.\n\n### 4. Download And Playback\n\n- Wire provider direct download URLs in `src/aliapi/file.ts` `ApiFileDownloadUrl`.\n- Third-party drives usually do not have Aliyun transcode APIs; `ApiVideoPreviewUrl` / `ApiAudioPreviewUrl` should return `暂无转码信息` or `undefined`, letting playback use the raw download URL.\n- Wire same-directory playlist loading in `src/layout/PageVideo.vue`, `src/utils/openfile.ts`, and `src/utils/playerhelper.ts`.\n- Confirm clicking provider videos does not call Aliyun APIs.\n\n### 5. Search\n\n- Add `src/<provider>/search.ts`.\n- Support keyword search.\n- If the existing UI uses special `file_id` values for search conditions, implement parse/build/filter helpers.\n- Wire search-directory branches in `src/pan/pandal.ts`.\n\n### 6. Thumbnails And Preview\n\n- Prefer thumbnails returned by list/detail APIs.\n- If the provider needs a separate thumbnail API, add `src/<provider>/thumbnail.ts`.\n- Fill `thumbnail` during file mapping so media library and file lists can use it directly.\n\n### 7. File Operations\n\n- Add `src/<provider>/filecmd.ts`.\n- Implement create folder, move to recycle bin, permanent delete, rename, move, and copy. Clearly report unsupported official capabilities.\n- Wire `ApiCreatNewForder`, `ApiTrashBatch`, `ApiDeleteBatch`, `ApiRenameBatch`, `ApiMoveBatch`, and `ApiCopyBatch` in `src/aliapi/filecmd.ts`.\n- Unsupported capabilities must not fall through to the Aliyun default branch.\n\n### 8. Sharing\n\n- Add `src/<provider>/share.ts` with share-link creation.\n- If the provider does not support password, expiration, or multi-file sharing, block it clearly in `src/aliapi/share.ts`.\n- Update context-menu and top-menu share visibility.\n\n### 9. Upload And New Files\n\n- Add or extend `src/<provider>/upload.ts`.\n- Implement in-memory upload for new text files.\n- Implement local-file upload worker support for ordinary file/folder uploads.\n- Implement large files using the provider-recommended session/chunk API.\n- Wire `src/aliapi/uploadmem.ts` and `src/workerpage/uploader.ts`.\n- Third-party drives do not support app custom encrypted/private uploads by default; hide those menu items.\n\n### 10. Media Library Scanning\n\n- Wire provider folder traversal in `src/utils/mediaScanner.ts`.\n- Wire provider subfolder entry in `src/components/MediaLibrary.vue`.\n- Show the provider name in media-library source labels.\n- Confirm scanning does not call Aliyun list APIs.\n\n### 11. Folder Picker Modal\n\n- Treat the provider as a single-root drive in `src/pan/topbtns/SelectPanDirModal.vue`.\n- Wire lazy child directory loading.\n- Move, copy, and save-location picker modals must browse provider directories.\n\n### 12. Menu Capability Boundaries\n\n- Update `src/pan/menus/FileRightMenu.vue`, `src/pan/menus/FileTopbtn.vue`, `src/pan/menus/DirLeftMenu.vue`, and `src/pan/menus/PanTopbtn.vue`.\n- Show common capabilities: download, share, rename, move to, copy to, delete, properties, scan media library, normal upload, and normal new file/folder.\n- Hide Aliyun-only capabilities: lucky bottle, fast transfer, favorite, transcode-related actions, mark encrypted, clear history, color labels, copy directory tree, encrypted/private new file, encrypted/private upload, and import share.\n\n### 13. Properties, Versions, And Recycle Bin\n\n- Wire provider file detail in `src/pan/topbtns/ShuXingModal.vue`.\n- If folder size has no official API, return 0 or hide it; do not call Aliyun folder-size APIs.\n- If the provider supports file versions, add `src/<provider>/revisions.ts` and expose version listing/restoration in properties.\n- If the provider supports recycle bin list/restore, add `src/<provider>/recyclebin.ts` and wire recycle-bin directory, restore, and permanent delete.\n- If the official API supports only some account types or needs higher permissions, record the limitation and keep it disabled by default.\n\n### 14. Tests\n\n- Add provider helper tests under `src/<provider>/__tests__/`.\n- Cover at least OAuth URL/token body, file-list path/body, model mapping, search path/body, share body/result mapping, file-operation body, upload session/chunk path, and version/recycle-bin path where applicable.\n- Update `vitest.config.ts` to include provider tests.\n\n### 15. Verification\n\n- Run provider unit tests.\n- Run `pnpm run build`.\n- If playback/media library is involved, verify provider videos use provider download URLs, same-directory playlists use provider list APIs, media-library scans use provider list APIs, and context menus do not expose unsupported capabilities.\n\n### Recommended File Structure\n\n```text\nsrc/<provider>/\n  auth.ts\n  dirfilelist.ts\n  filecmd.ts\n  search.ts\n  share.ts\n  upload.ts\n  revisions.ts       # optional\n  recyclebin.ts      # optional\n  thumbnail.ts       # optional\n  __tests__/\n```\n\n### Completion Criteria\n\n- Login and token refresh work.\n- The left tree shows root and folders.\n- File list opens root, subdirectories, and search results.\n- File detail, download, and video playback do not call the wrong provider API.\n- Context menus and top menus expose only supported capabilities.\n- Create folder, rename, move, copy, and delete call provider APIs.\n- Share, upload, and media-library scanning are wired or explicitly reported unsupported.\n- Provider unit tests pass.\n- `pnpm run build` passes.\n\n### Current Experience Notes\n\n- Dropbox and OneDrive should both be treated as single-root third-party drives.\n- Third-party drive video playback should prefer raw download URLs and must not reuse Aliyun transcode APIs.\n- Media-library scanning and same-directory playlists are the easiest provider branches to miss.\n- Auth pages should usually open in the system browser unless the provider explicitly requires an embedded flow.\n- App key / secret placeholder constants must be included in the generated-secrets flow, not committed as real values.\n\n## Cloud Download URL And Subtitle Contract\n\nTreat a cloud download URL and its request headers as one value. `ApiFileDownloadUrl` must return every provider-required header in `IDownloadUrl.headers`; callers must preserve those headers through playback, downloads, previews, and subtitles.\n\n| Provider | Download request requirements |\n|---|---|\n| Aliyun / Alipan | Signed CDN URL; Electron may add the Aliyun Referer/Origin for direct renderer requests. |\n| 115 | `Authorization: Bearer <account token>` and `DRIVE115_DOWN_AGENT`. The User-Agent used to consume the URL must match the one used to obtain it. Direct renderer playback must register URL-to-account auth context; never rely only on the currently selected account. |\n| Baidu | URL includes `access_token`; send `User-Agent: pan.baidu.com` and `Referer: https://pan.baidu.com/`. |\n| 123 | The returned signed download URL is self-authorizing; API Authorization is only for obtaining the URL. |\n| Quark | Account Cookie plus Quark download User-Agent, `Referer: https://pan.quark.cn/`, `Origin: https://pan.quark.cn`, and `x-urlp` when required by the OSS URL. |\n| 139 | `cloud139DownloadHeaders()`: provider User-Agent, Referer, and Origin. |\n| 189 | `cloud189DownloadHeaders()`: provider User-Agent and Referer. |\n| PikPak | Temporary download/stream URL returned by the provider. |\n| Dropbox / OneDrive | Temporary or pre-authenticated download URL returned by the provider. |\n| Box | Access token is encoded into the constructed download URL. |\n\nSubtitle rules:\n- Same-directory cloud subtitles must use `ApiFileDownloadUrl`; never fetch a guessed provider URL directly.\n- The web player and external players must use the subtitle-specific local proxy URL and pass `IDownloadUrl.headers` as `proxy_headers`.\n- The subtitle proxy must identify the account with `user_id` and the provider with `drive_id`; do not use a global/current-account token when an account-specific token is available.\n- Video streams remain direct URLs unless encryption requires the proxy. DLNA behavior is separate and must not be changed as part of subtitle or direct-play fixes.\n- Any provider download-header change requires regression coverage for both the video/download URL contract and same-directory subtitle loading.\n\n## clouddrive-cli\n\nStandalone CLI + MCP server for agent-driven cloud-drive operations. Docs: `clouddrive-cli/README.md`. The CLI supports 8 providers and has its own npm package (`clouddrive-cli`). Separate test command: `pnpm run test:clouddrive-cli`.\n\n## CI\n\nManual trigger only (`workflow_dispatch`) via `.github/workflows/release.yml`. Builds on `windows-latest` + `ubuntu-latest`, publishes draft GitHub Release. No automatic CI on push/PR.\n\n### Release ownership: drafts only\n\n- The human user owns the final publication of every GitHub Release. The agent and CI may prepare commits/tags, build and upload assets, and create/update **draft releases only** when requested.\n- Requests such as “发布 release”, “更新 release”, “重新提交代码更新 release”, or “继续发布” mean prepare/update a draft; they do **not** authorize making it public. The user publishes it manually in GitHub.\n- Never run `gh release edit --draft=false`, create a non-draft release, or enable automatic publication in a workflow or packaging configuration. Keep electron-builder `releaseType` set to `draft` and the workflow's final release update in draft state.\n- Do not delete, recreate, demote, overwrite assets on, or otherwise modify an already-public release without a separate explicit request for that exact operation. A rerun targeting a public tag must stop rather than modify that release.\n- Determine the next version from the latest **public** release plus one patch version, unless the user explicitly specifies a different version. Do not move an existing public tag to new code.\n- Report draft creation and build/test status accurately. Never describe a draft or queued workflow as a published release.\n\n## Subprojects (gitignored, referenced locally)\n\n`Motrix/`, `koodo-reader/`, `CloudServiceKit/`, `XbyVideoHub/`, `OpenCLI/`, `QuarkPan/`, `PikPakAPI/` — these are local-only and not part of the main repo build.\n"},"files":{"clouddrive-cli/skill/SKILL.md":"---\nname: clouddrive-cli\ndescription: Use when an agent needs to operate cloud-drive accounts through clouddrive-cli or clouddrive-mcp: discover logged-in accounts, inspect/list/walk/search cloud files, read local documents as context, generate or apply safe media rename/move/trash/upload/organize plans, and roll back supported operations.\nallowed-tools:\n  - Bash(clouddrive-cli:*)\n  - Bash(clouddrive-mcp:*)\n  - Read\n---\n\n# clouddrive-cli\n\n`clouddrive-cli` turns BoxPlayer cloud-drive accounts into a deterministic command surface for humans and AI agents. It supports Aliyun Drive, OneDrive, Dropbox, Box, 123Pan, 115 Drive, Baidu Netdisk, and PikPak.\n\nThis skill is the orientation layer. Discover the live CLI surface first, then choose the smallest safe command path for the user's goal.\n\n## The three pillars\n\n- **Account and provider discovery** — `auth list`, `settings show`, and `providers capabilities` tell you which accounts exist and which operations each provider supports.\n- **Cloud file operations** — `files list|walk|tree|stats|info|download|search|mkdir|rename-apply|move-apply|trash-apply` provide the stable boundary for reading and changing cloud files.\n- **Agent workflows** — `docs read`, `media *`, `upload *`, `organize *`, and `ops *` let agents combine local instructions, cloud inventory, dry-run plans, execution, and rollback.\n\n## Install and locate\n\n```bash\nwhich clouddrive-cli\nclouddrive-cli --help\nclouddrive-cli list --format json\n```\n\nIf the command is missing, ask the user to install it from BoxPlayer account settings or with `npm install -g clouddrive-cli`.\n\nThere are two install modes:\n\n- **BoxPlayer app mode** — the Electron app registers `clouddrive-cli` and exports logged-in account tokens.\n- **Standalone CLI mode** — install with npm and use `auth login` or `auth import-token` to add accounts.\n\n## Discover first\n\nDo not treat this file as the complete command registry. Start with live discovery:\n\n```bash\nclouddrive-cli list --format json\nclouddrive-cli schema commands\nclouddrive-cli auth list --format json\nclouddrive-cli settings show --format json\nclouddrive-cli providers capabilities --format json\n```\n\n`clouddrive-cli list --format json` is the source of truth for command metadata such as `access`, `requiresDryRun`, `destructive`, and `undoable`. `providers capabilities` is the source of truth for provider-specific support such as search, mkdir, move, rename, trash/delete, upload, recursive walk, path addressing, and file-id addressing.\n\n## Universal conventions\n\n| convention | meaning |\n|------------|---------|\n| `--format json` / `--json` | Agent-friendly JSON output. Prefer this by default. |\n| JSON errors | Failures return `{ ok: false, error: { code, message, exitCode } }` in JSON mode. Branch on `error.code`, not message text. |\n| dry-run first | Commands marked `requiresDryRun` must be previewed before execution. |\n| capability check | Before mkdir, move, rename, trash, upload, or organize apply, check `providers capabilities`. |\n| large output | Commands with `largeOutput: true` should use `--output <file.json>` so stdout stays a compact summary. |\n| rationale | Write commands accept `--rationale <reason>`; use it to preserve why the Agent is acting. |\n| no invented IDs | Get file IDs from `files list`, `files walk`, `files search`, `files tree`, or `files info`. |\n\nCommon error codes:\n\n| code | meaning | response |\n|------|---------|----------|\n| `AUTH_ERROR` | Missing/expired account or login failure. | Run `auth list`, `auth check`, `auth login`, or ask for token import. |\n| `PROVIDER_API_ERROR` | Provider returned an API/HTTP error. | Retry only if transient; otherwise record provider limitation. |\n| `UNSUPPORTED_CAPABILITY` | Provider or command capability is unavailable. | Stop or choose a supported fallback. |\n| `VALIDATION_ERROR` | Bad args, missing files, invalid plan, unknown operation. | Fix input before retrying. |\n\n## Read workflows\n\nUse bounded reads before large traversals:\n\n```bash\nclouddrive-cli files stats --provider aliyun --account default --file-id root --depth 2 --format json\nclouddrive-cli files stats --provider aliyun --account default --file-id root --output stats.json --format json\nclouddrive-cli files tree --provider aliyun --account default --file-id root --depth 1\nclouddrive-cli files list --provider aliyun --account default --file-id root --format json\nclouddrive-cli files list --provider aliyun --account default --file-id root --limit 100 --format json\nclouddrive-cli files list --provider aliyun --account default --file-id root --limit 100 --cursor <nextCursor> --format json\nclouddrive-cli files download --provider aliyun --account default --file-id <file-id> --output ./download.bin --format json\nclouddrive-cli files search --provider aliyun --account default --name \"movie\" --limit 50 --format json\n```\n\nRules of thumb:\n\n- Use `stats` or shallow `tree` to understand scale.\n- Use `search` for known keywords.\n- Use `walk` only after narrowing scope or when a full inventory is explicitly needed.\n- Avoid raw `files tree --json` and broad `walk` on large roots unless you will save and summarize the output locally.\n\nProvider root defaults when `--file-id` is omitted:\n\n| provider | default root |\n|----------|--------------|\n| aliyun | `root` |\n| cloud123 | `0` |\n| 115 | `0` |\n| baidu | `/` |\n| pikpak | `*` |\n| dropbox | empty string |\n| onedrive | `onedrive_root` |\n| box | `box_root` |\n\n## Write workflows\n\nNever apply a write plan first. The safe sequence is:\n\n1. Discover command metadata with `clouddrive-cli list --format json`.\n2. Check provider capability with `clouddrive-cli providers capabilities --format json`.\n3. Generate or read a plan.\n4. Run the dry-run or preview command.\n5. Show the user a concise summary of planned changes.\n6. Execute only after explicit user approval.\n7. Record the operation ID and rollback path when available.\n\nInclude `--rationale` on write commands, for example:\n\n```bash\nclouddrive-cli upload apply upload-plan.json --dry-run --rationale \"User asked to back up this folder\" --format json\n```\n\nCommon write previews:\n\n```bash\nclouddrive-cli files rename-apply rename-plan.json --current files.json --dry-run --format json\nclouddrive-cli files move-apply move-plan.json --dry-run --format json\nclouddrive-cli files trash-apply trash-plan.json --format json\nclouddrive-cli upload apply upload-plan.json --dry-run --format json\nclouddrive-cli organize apply organize-plan.json --dry-run --summary --format json\n```\n\nNotes:\n\n- `trash-apply` defaults to preview; execution requires `--apply`.\n- Rename and move operations are undoable through `ops undo`; trash is not.\n- Dropbox and Baidu move/trash plans may require path fields in addition to file IDs.\n- Upload planning exists for all providers. Real byte upload is wired for providers whose `providers capabilities` entry has `uploadFile: true` (`aliyun`, `cloud123`, `115`, `baidu`, `dropbox`, `onedrive`, `box` in this build); `pikpak` remains plan/dry-run only.\n\n## Media organization\n\nRecommended flow:\n\n```bash\nclouddrive-cli docs read ./rules.md --max-chars 50000 --format json\nclouddrive-cli docs read ./rules.pdf --pdf-format markdown --pdf-pages 1-3 --format json\nclouddrive-cli docs convert ./pdf-folder --output ./out --pdf-format json,html,pdf,markdown,tagged-pdf,text --format json\nclouddrive-cli files stats --provider aliyun --account default --file-id <folder-id> --depth 2 --format json\nclouddrive-cli files walk --provider aliyun --account default --file-id <folder-id> --output files.json --format json\nclouddrive-cli media match --input files.json --format json\n# Generate rename-plan.json yourself from rules, inventory, and match output.\nclouddrive-cli files rename-apply rename-plan.json --dry-run --format json\n```\n\n`media match` returns media fields under `match`, for example `{ fileId, name, match: { type, title, year, season, episode, confidence, jellyfin_name } }`.\n\nFor full-drive organization, treat broad plans as risky even if dry-run succeeds. Sample suspicious moves, check whether existing meaningful folders would be flattened into generic `Movies` or `TV Shows`, and prefer applying one folder/category at a time.\n\n## Rollback\n\n```bash\nclouddrive-cli ops list --format json\nclouddrive-cli ops show <operation-id> --format json\nclouddrive-cli ops undo <operation-id> --dry-run --format json\nclouddrive-cli ops undo <operation-id> --format json\n```\n\nAlways run `ops undo --dry-run` first. Only rename and move operations have CLI undo.\n\n## MCP\n\n`clouddrive-mcp` exposes the CLI manifest as MCP tools. Tool names and input schemas are generated from the same command manifest used by `clouddrive-cli list --format json`, so CLI/MCP discovery should stay aligned. Prefer direct CLI commands when:\n\n- You need file output redirection or plan files.\n- You are testing CLI behavior during skill/CLI iteration.\n\n## Known provider limitations\n\n- OneDrive `files search` may intermittently fail with Microsoft Graph `generalException` / HTTP 500. Use `files walk` plus local filtering as fallback.\n- PikPak `files search --name` may ignore the name query and return root items. Use `files walk` plus local filtering.\n- Baidu `files info` handles `filemetas` under either `list` or `info`, but `errno=12` can still indicate an API/token limitation. Fall back to `files walk` or `files search`.\n- 115 Open API folder fields may map folders as `type: file`. Confirm folder-ness by trying `files list --file-id <fileId>` before planning folder operations.\n\n## Don't\n\n- Don't paste this skill's command list into a plan; call `clouddrive-cli list --format json`.\n- Don't run non-dry-run writes without explicit user approval.\n- Don't assume root path tokens are portable across providers.\n- Don't continue after a structured JSON error without branching on `error.code`.\n- Don't emit huge raw inventories to the user; save, summarize, and sample.\n","CLAUDE.md":"# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Quick commands\n\n```bash\npnpm install          # pnpm only — never npm/yarn\npnpm dev              # hot-reload Electron dev server (Vite + vue-tsc)\npnpm run build        # version bump → typecheck → vite bundle\npnpm run build:electron  # full build + electron-builder packaging\npnpm run test         # focused Vitest suite (Node env, aria2 + motrix + utils)\npnpm run test:clouddrive-cli  # clouddrive-cli tests only\npnpm run build:mac    # unsigned macOS .dmg/.zip\npnpm run build:mac:signed  # signed + notarized macOS\npnpm run build:linux  # Linux .deb/.AppImage/.pacman\npnpm run build:windows  # Windows .exe/.zip\npnpm run build:all    # cross-platform sequentially\npnpm run config:clean     # blank API keys in src/config.ts (pre-commit hook)\npnpm run config:restore   # restore real keys after commit\n```\n\n## Architecture (Electron + Vue 3 + Vite)\n\n```\nelectron/main/       Electron main process (entry: electron/main/index.ts)\n  core/              Window lifecycle, IPC, auto-update, protocol, dialogs\n  aria/              Aria2c download engine (config, UPnP, runtime)\nelectron/preload/    Preload scripts (IPC bridge)\n\nsrc/                 Vue 3 renderer\n  aliapi/            Alibaba Cloud Drive SDK (files, share, user, etc.)\n  cloudbaidu/        Baidu Netdisk provider\n  cloud123/          123Pan provider\n  cloud115/          115Pan provider\n  pikpak/            PikPak provider\n  onedrive/          OneDrive provider\n  dropbox/           Dropbox provider\n  box/               Box provider\n  quark/             Quark provider\n  cloud139/          CMCloud provider\n  cloud189/          Tianyi Cloud provider\n  pan/               File manager UI (tree, menus, dialogs)\n  media-server/      Jellyfin/Emby/Plex integration\n  down/              Download manager + Aria2 integration\n  layout/            Main layout views (PageVideo, PageMusic, etc.)\n  module/            Feature modules (audioplayer, musicsdk, lyricplayer, theme)\n  store/             Pinia stores\n  components/        Shared Vue components\n  utils/             Shared utilities\n  user/              Auth, account management UI\n\nshared/              Code shared between main + renderer (constants, config keys, UA)\nscripts/             Build scripts, CLI entry points (clouddrive-cli.mjs, clouddrive-mcp.mjs)\nclouddrive-cli/      Standalone CLI + MCP server package (npm: clouddrive-cli)\n  core/              Command implementations, MCP server, upload planning\n  providers/         8 cloud-drive provider implementations\n  media/             Media matching + rename logic\n```\n\nPath aliases: `@shared/*` → `shared/*`, `@main/*` → `electron/main/*`\n\n## Key patterns\n\n- **pnpm only** — lockfile is `pnpm-lock.yaml`; `package-lock.json`/`yarn.lock` are gitignored\n- **Node ≥ 18**\n- **Pre-commit hooks** (`nano-staged.mjs`): prettier + eslint on JS/TS, stylelint + prettier on Vue/CSS, typecheck on changed `src/` files\n- **Formatting**: single quotes, no semicolons, 260 printWidth, no trailing commas, LF, `sortAttributes: true` in Vue\n- **TypeScript**: strict mode, ESNext target, node moduleResolution\n- **Sensitive config**: `scripts/clean-config.js` blanks API keys pre-commit; restore with `pnpm run config:restore`\n- **Vitest**: Node environment only, explicit test directory list in `vitest.config.ts` (not glob patterns). Add new test dirs to config.\n- **CI**: Manual trigger only via `.github/workflows/release.yml`, publishes draft GitHub Release\n\n## clouddrive-cli (AI agent integration)\n\nStandalone CLI + MCP server for agent-driven cloud-drive operations. Supports 8 providers: aliyun, cloud123, 115, baidu, pikpak, onedrive, box, dropbox.\n\nKey bins: `clouddrive-cli` (CLI), `clouddrive-mcp` (MCP server). Both point to `scripts/clouddrive-cli.mjs` and `scripts/clouddrive-mcp.mjs` respectively.\n\nAgent rules when using the CLI:\n1. Discover commands first: `clouddrive-cli list --format json`\n2. Check capabilities: `clouddrive-cli providers capabilities --format json`\n3. Always dry-run before destructive ops\n4. Never invent file IDs — they must come from `files list`/`walk`/`search`/`tree`\n5. Use `--output <file.json>` for large results\n\n## Adding a new cloud-drive provider\n\nFollow the 15-step checklist in `AGENT.md` (OAuth → provider detection → file listing → download/playback → search → thumbnails → file operations → sharing → upload → media scan → folder picker → menu boundaries → properties/recycle bin → tests → verification). The checklist is authoritative — do not ship a provider that only does file listing.\n","AGENTS.md":"# AGENTS.md — BoxPlayer (aliyunpan)\n\n## “All Platforms” Scope\n\n- When the user says “all platforms” (`所有平台`), treat it as one request spanning all three repositories: `~/aliyunpan`, `~/BoxPlayer_Android`, and `~/XbyVideoHub`.\n- Implement the Electron/aliyunpan surface in `~/aliyunpan`; implement Android phone, tablet, and Android TV in `~/BoxPlayer_Android`; implement macOS, iOS/iPadOS, and tvOS in `~/XbyVideoHub`.\n- Inspect and modify each repository independently. Do not assume a change in one repository propagates to the other two.\n\n## Quick reference\n\n```bash\npnpm install          # install deps (pnpm only, never npm/yarn)\npnpm dev              # hot-reload Electron dev server\npnpm run build        # typecheck + bundle (vue-tsc --noEmit && vite build)\npnpm run test         # focused Vitest suite (not full repo)\npnpm run test:clouddrive-cli  # clouddrive-cli tests only\n```\n\n## Home Category Context Menus\n\n- Categories and independently placeable subcategories, including series, playlists, movie/TV child categories, genre, rating, score, and release-date values, use the same placement context-menu state machine.\n- An unplaced item shows “Add to Home” and “Add to Favorites”; both actions prompt for a user-defined display name.\n- After either add action succeeds, or when the item is initially visible on Home, the menu immediately switches to “Remove from Home” and “Rename Favorite.” The menu must not allow simultaneous Home and Favorites placement.\n- “Remove from Home” clears whichever placement contains the item. Renaming a favorite changes only its Favorites card title and does not rename the Home or sidebar title.\n\n## Package manager: pnpm only\n\nLockfile is `pnpm-lock.yaml`. `package-lock.json` and `yarn.lock` are in `.gitignore`.\nNever use `npm install` or `yarn`.\n\n## Node version\n\n`engines.node >= 22.12.0` in package.json. Electron 40 requires Node 22.12+ during install/build.\n\n## Build pipeline order matters\n\n`pnpm run build` runs **version bump → typecheck → vite bundle**. The version bump (`version.mjs`) auto-increments the patch version in package.json before every build. The build removes `dist/` and `release/` directories on start.\n\n`pnpm run build:electron` calls `build` first, then runs `electron-builder`.\n\nFor platform-specific packaging:\n```bash\npnpm run build:mac       # unsigned macOS\npnpm run build:mac:signed  # signed + notarized\npnpm run build:linux\npnpm run build:windows\npnpm run build:all       # cross-platform, sequential\n```\n\n## Sensitive config: generated secrets\n\nPrivate client IDs, client secrets, API keys, and private API URLs live outside git:\n\n```bash\npnpm run secrets:generate\n```\n\nLocal development reads them from `.env.local` and generates `src/secrets.generated.ts`. GitHub Actions reads the same keys from GitHub Secrets and runs `scripts/generate-secrets.mjs --mode=ci --strict` before building.\n\n`.env.local` and `src/secrets.generated.ts` are ignored and must never be committed. `src/config.ts` should import generated secrets or use placeholders, not contain real private values.\n\n## Architecture: Electron + Vue 3 + Vite\n\n| Directory | Purpose |\n|---|---|\n| `electron/main/` | Electron main process (entry: `electron/main/index.ts`) |\n| `electron/preload/` | Preload scripts |\n| `src/` | Vue 3 renderer (components, views, stores, API modules) |\n| `shared/` | Code shared between main + renderer |\n| `scripts/` | Build, CLI entry points, config management |\n| `clouddrive-cli/` | Standalone CLI package (published to npm as `clouddrive-cli`) |\n\nPath aliases (set in `tsconfig.json`, `vite.config.ts`, `vitest.config.ts`):\n- `@shared/*` → `shared/*`\n- `@main/*` → `electron/main/*`\n\nCloud provider API modules in `src/`: `aliapi/`, `cloudbaidu/`, `cloud123/`, `cloud115/`, `pikpak/`, `onedrive/`, `box/`, `dropbox/`, `quark/`, `cloud139/`, `cloud189/`.\n\n## GitHub Issue workflow\n\nWhen the user asks to handle GitHub Issues, first fetch the complete list of unfinished/open Issues in the requested repository. Review each Issue individually, identify its likely cause and affected code, and report the triage before changing code. Then implement fixes and run focused regression tests for each applicable Issue. Do not jump straight into a code change based only on the newest Issue or close an Issue before its fix is verified. If the repository or Issue access is unavailable, state that limitation rather than assuming the list is complete.\n\n## Testing: Vitest, Node environment, selective includes\n\n### Default app inspection: attach to the existing dev app\n\n- Unless the user explicitly asks to execute E2E tests, always connect to the app the user already started with `pnpm run dev` for inspection, reproduction, debugging, and UI verification.\n- Use the existing Electron CDP endpoint (normally `http://127.0.0.1:9223`; confirm the active endpoint). Playwright may attach with `chromium.connectOverCDP`; do not use `electron.launch`, spawn another Electron process, or start another `pnpm run dev` instance.\n- Preserve the running app's real user-data directory, accounts, settings, and playback state. Do not substitute an isolated/temporary profile or seed test data into the user's app.\n- Requests to review, investigate, reproduce, fix, or verify a bug are not explicit requests to run E2E tests. Do not automatically run `pretest:e2e`, `test:e2e`, or Playwright specs whose fixtures launch a separate app.\n- If the existing app or relevant window is unavailable, report that and ask the user to start/reopen it. Do not silently launch a replacement. Request approval before restarting the user's dev app when a main-process or native-module change requires it.\n- This rule takes precedence over the E2E workflow below. Record what was actually verified in the existing dev app; do not describe attached-session checks as production E2E acceptance. A pending E2E gate does not authorize launching another app.\n\n### Playwright acceptance gate when E2E execution is explicitly requested\n\nWhen the user explicitly asks to execute E2E tests, verify bug fixes through Playwright against an actually launched Electron application using the workflow below. Unit tests, type checks, source inspection, and merely starting `pnpm run dev` cannot replace this E2E gate.\n\n1. Add or update a Playwright regression test that reproduces the reported failure through the user-visible application flow.\n2. Build the production Electron entry with `pnpm run pretest:e2e`; do not test stale `dist/` output or an installed older BoxPlayer build.\n3. Run the focused Playwright regression test and record the exact command and result.\n4. For cloud-drive bugs, use the configured real account and exercise the real provider API. Do not skip the relevant real-account case or replace it with mocks.\n5. For platform-specific behavior that cannot execute on the current host, run Playwright on the target platform before calling the bug fixed. If that is unavailable, report the fix as unverified/blocked rather than complete.\n6. A failed, skipped, or unexecuted Playwright regression test blocks declaring the bug fixed and blocks release publication.\n\nKeep the regression test after the fix so the same bug cannot silently return.\n\nTests run in Node environment (not jsdom). The `vitest.config.ts` lists explicit test directories — not a glob over `**/*.test.ts`. Tests outside these paths are not picked up:\n\n- `electron/main/core/__tests__/`, `electron/main/aria/__tests__/`\n- `shared/__tests__/`, `scripts/__tests__/`\n- `src/down/motrix-integration/`, `src/media-server/__tests__/`\n- `src/utils/__tests__/`, `src/aliapi/__tests__/`\n- `src/pikpak/__tests__/`, `src/quark/__tests__/`\n- `src/dropbox/__tests__/`, `src/onedrive/__tests__/`, `src/box/__tests__/`\n- `clouddrive-cli/__tests__/`\n\nDefault `pnpm run test` runs only a subset (aria2 tests, motrix integration, a couple utils files).\n\nWhen adding tests in a new directory, update `vitest.config.ts`.\n\n## Pre-commit hooks\n\nDo not rely on pre-commit cleanup for secrets. Secret safety is handled by keeping real values in ignored/generated files and GitHub Secrets.\n\n## Formatting conventions\n\nFrom `.prettierrc`:\n- Single quotes, no semicolons\n- 260 printWidth (very wide)\n- No trailing commas\n- LF line endings\n- `sortAttributes: true` on HTML/Vue\n\n## TypeScript\n\n- `tsconfig.json` targets ESNext, moduleResolution node, strict mode, `@shared/*` and `@main/*` path aliases\n- Includes `src/` and `shared/`, excludes `shared/__tests__`\n- References `tsconfig.node.json` for Electron-side code\n\n## Provider Integration Checklist\n\nWhen adding a new cloud-drive provider, implement the following in order unless the user explicitly excludes a step. Do not stop after only wiring file listing. Sync/change-listening is not required by default.\n\n### 1. Account And Auth\n\n- Read the official OAuth/API documentation and prefer stable API versions.\n- Add `src/<provider>/auth.ts` with auth URL, authorization-code token exchange, and refresh token support.\n- Define `CLIENT_ID` / `CLIENT_SECRET` placeholder constants, defaulting to empty strings.\n- Add app key / secret fields to `.env.example`, `src/secrets.example.ts`, and `scripts/generate-secrets.mjs`.\n- Add the provider to `tokenfrom` in `src/user/userstore.ts`.\n- Wire login, token refresh, and drive loading in `src/user/userdal.ts`.\n- Add login entry points in `src/user/UserLogin.vue` and `src/user/UserInfo.vue`.\n\n### 2. Provider Detection And Drive Model\n\n- Add `is<Provider>User` in `src/aliapi/utils.ts`.\n- Update `GetDriveID` and `GetDriveType`, modeling third-party drives as a single-root drive.\n- Filter unsupported virtual directories in `src/pan/PanLeft.vue` and `src/pan/pantreestore.ts`.\n\n### 3. File List And Detail\n\n- Add `src/<provider>/dirfilelist.ts`.\n- Implement root listing, child directory pagination, and file detail.\n- Map official file models to `IAliGetFileModel`; at minimum fill `drive_id`, `file_id`, `parent_file_id`, `name`, `isDir`, `category`, `icon`, `size`, `time`, `thumbnail`, and `content_hash`.\n- Store provider-specific path, parent id, download URL, or similar metadata in `description`.\n- Wire root loading, directory listing, and search-listing branches in `src/pan/pandal.ts`.\n- Wire provider file detail in `src/aliapi/file.ts` `ApiFileInfo`.\n\n### 4. Download And Playback\n\n- Wire provider direct download URLs in `src/aliapi/file.ts` `ApiFileDownloadUrl`.\n- Third-party drives usually do not have Aliyun transcode APIs; `ApiVideoPreviewUrl` / `ApiAudioPreviewUrl` should return `暂无转码信息` or `undefined`, letting playback use the raw download URL.\n- Wire same-directory playlist loading in `src/layout/PageVideo.vue`, `src/utils/openfile.ts`, and `src/utils/playerhelper.ts`.\n- Confirm clicking provider videos does not call Aliyun APIs.\n\n### 5. Search\n\n- Add `src/<provider>/search.ts`.\n- Support keyword search.\n- If the existing UI uses special `file_id` values for search conditions, implement parse/build/filter helpers.\n- Wire search-directory branches in `src/pan/pandal.ts`.\n\n### 6. Thumbnails And Preview\n\n- Prefer thumbnails returned by list/detail APIs.\n- If the provider needs a separate thumbnail API, add `src/<provider>/thumbnail.ts`.\n- Fill `thumbnail` during file mapping so media library and file lists can use it directly.\n\n### 7. File Operations\n\n- Add `src/<provider>/filecmd.ts`.\n- Implement create folder, move to recycle bin, permanent delete, rename, move, and copy. Clearly report unsupported official capabilities.\n- Wire `ApiCreatNewForder`, `ApiTrashBatch`, `ApiDeleteBatch`, `ApiRenameBatch`, `ApiMoveBatch`, and `ApiCopyBatch` in `src/aliapi/filecmd.ts`.\n- Unsupported capabilities must not fall through to the Aliyun default branch.\n\n### 8. Sharing\n\n- Add `src/<provider>/share.ts` with share-link creation.\n- If the provider does not support password, expiration, or multi-file sharing, block it clearly in `src/aliapi/share.ts`.\n- Update context-menu and top-menu share visibility.\n\n### 9. Upload And New Files\n\n- Add or extend `src/<provider>/upload.ts`.\n- Implement in-memory upload for new text files.\n- Implement local-file upload worker support for ordinary file/folder uploads.\n- Implement large files using the provider-recommended session/chunk API.\n- Wire `src/aliapi/uploadmem.ts` and `src/workerpage/uploader.ts`.\n- Third-party drives do not support app custom encrypted/private uploads by default; hide those menu items.\n\n### 10. Media Library Scanning\n\n- Wire provider folder traversal in `src/utils/mediaScanner.ts`.\n- Wire provider subfolder entry in `src/components/MediaLibrary.vue`.\n- Show the provider name in media-library source labels.\n- Confirm scanning does not call Aliyun list APIs.\n\n### 11. Folder Picker Modal\n\n- Treat the provider as a single-root drive in `src/pan/topbtns/SelectPanDirModal.vue`.\n- Wire lazy child directory loading.\n- Move, copy, and save-location picker modals must browse provider directories.\n\n### 12. Menu Capability Boundaries\n\n- Update `src/pan/menus/FileRightMenu.vue`, `src/pan/menus/FileTopbtn.vue`, `src/pan/menus/DirLeftMenu.vue`, and `src/pan/menus/PanTopbtn.vue`.\n- Show common capabilities: download, share, rename, move to, copy to, delete, properties, scan media library, normal upload, and normal new file/folder.\n- Hide Aliyun-only capabilities: lucky bottle, fast transfer, favorite, transcode-related actions, mark encrypted, clear history, color labels, copy directory tree, encrypted/private new file, encrypted/private upload, and import share.\n\n### 13. Properties, Versions, And Recycle Bin\n\n- Wire provider file detail in `src/pan/topbtns/ShuXingModal.vue`.\n- If folder size has no official API, return 0 or hide it; do not call Aliyun folder-size APIs.\n- If the provider supports file versions, add `src/<provider>/revisions.ts` and expose version listing/restoration in properties.\n- If the provider supports recycle bin list/restore, add `src/<provider>/recyclebin.ts` and wire recycle-bin directory, restore, and permanent delete.\n- If the official API supports only some account types or needs higher permissions, record the limitation and keep it disabled by default.\n\n### 14. Tests\n\n- Add provider helper tests under `src/<provider>/__tests__/`.\n- Cover at least OAuth URL/token body, file-list path/body, model mapping, search path/body, share body/result mapping, file-operation body, upload session/chunk path, and version/recycle-bin path where applicable.\n- Update `vitest.config.ts` to include provider tests.\n\n### 15. Verification\n\n- Run provider unit tests.\n- Run `pnpm run build`.\n- If playback/media library is involved, verify provider videos use provider download URLs, same-directory playlists use provider list APIs, media-library scans use provider list APIs, and context menus do not expose unsupported capabilities.\n\n### Recommended File Structure\n\n```text\nsrc/<provider>/\n  auth.ts\n  dirfilelist.ts\n  filecmd.ts\n  search.ts\n  share.ts\n  upload.ts\n  revisions.ts       # optional\n  recyclebin.ts      # optional\n  thumbnail.ts       # optional\n  __tests__/\n```\n\n### Completion Criteria\n\n- Login and token refresh work.\n- The left tree shows root and folders.\n- File list opens root, subdirectories, and search results.\n- File detail, download, and video playback do not call the wrong provider API.\n- Context menus and top menus expose only supported capabilities.\n- Create folder, rename, move, copy, and delete call provider APIs.\n- Share, upload, and media-library scanning are wired or explicitly reported unsupported.\n- Provider unit tests pass.\n- `pnpm run build` passes.\n\n### Current Experience Notes\n\n- Dropbox and OneDrive should both be treated as single-root third-party drives.\n- Third-party drive video playback should prefer raw download URLs and must not reuse Aliyun transcode APIs.\n- Media-library scanning and same-directory playlists are the easiest provider branches to miss.\n- Auth pages should usually open in the system browser unless the provider explicitly requires an embedded flow.\n- App key / secret placeholder constants must be included in the generated-secrets flow, not committed as real values.\n\n## Cloud Download URL And Subtitle Contract\n\nTreat a cloud download URL and its request headers as one value. `ApiFileDownloadUrl` must return every provider-required header in `IDownloadUrl.headers`; callers must preserve those headers through playback, downloads, previews, and subtitles.\n\n| Provider | Download request requirements |\n|---|---|\n| Aliyun / Alipan | Signed CDN URL; Electron may add the Aliyun Referer/Origin for direct renderer requests. |\n| 115 | `Authorization: Bearer <account token>` and `DRIVE115_DOWN_AGENT`. The User-Agent used to consume the URL must match the one used to obtain it. Direct renderer playback must register URL-to-account auth context; never rely only on the currently selected account. |\n| Baidu | URL includes `access_token`; send `User-Agent: pan.baidu.com` and `Referer: https://pan.baidu.com/`. |\n| 123 | The returned signed download URL is self-authorizing; API Authorization is only for obtaining the URL. |\n| Quark | Account Cookie plus Quark download User-Agent, `Referer: https://pan.quark.cn/`, `Origin: https://pan.quark.cn`, and `x-urlp` when required by the OSS URL. |\n| 139 | `cloud139DownloadHeaders()`: provider User-Agent, Referer, and Origin. |\n| 189 | `cloud189DownloadHeaders()`: provider User-Agent and Referer. |\n| PikPak | Temporary download/stream URL returned by the provider. |\n| Dropbox / OneDrive | Temporary or pre-authenticated download URL returned by the provider. |\n| Box | Access token is encoded into the constructed download URL. |\n\nSubtitle rules:\n- Same-directory cloud subtitles must use `ApiFileDownloadUrl`; never fetch a guessed provider URL directly.\n- The web player and external players must use the subtitle-specific local proxy URL and pass `IDownloadUrl.headers` as `proxy_headers`.\n- The subtitle proxy must identify the account with `user_id` and the provider with `drive_id`; do not use a global/current-account token when an account-specific token is available.\n- Video streams remain direct URLs unless encryption requires the proxy. DLNA behavior is separate and must not be changed as part of subtitle or direct-play fixes.\n- Any provider download-header change requires regression coverage for both the video/download URL contract and same-directory subtitle loading.\n\n## clouddrive-cli\n\nStandalone CLI + MCP server for agent-driven cloud-drive operations. Docs: `clouddrive-cli/README.md`. The CLI supports 8 providers and has its own npm package (`clouddrive-cli`). Separate test command: `pnpm run test:clouddrive-cli`.\n\n## CI\n\nManual trigger only (`workflow_dispatch`) via `.github/workflows/release.yml`. Builds on `windows-latest` + `ubuntu-latest`, publishes draft GitHub Release. No automatic CI on push/PR.\n\n### Release ownership: drafts only\n\n- The human user owns the final publication of every GitHub Release. The agent and CI may prepare commits/tags, build and upload assets, and create/update **draft releases only** when requested.\n- Requests such as “发布 release”, “更新 release”, “重新提交代码更新 release”, or “继续发布” mean prepare/update a draft; they do **not** authorize making it public. The user publishes it manually in GitHub.\n- Never run `gh release edit --draft=false`, create a non-draft release, or enable automatic publication in a workflow or packaging configuration. Keep electron-builder `releaseType` set to `draft` and the workflow's final release update in draft state.\n- Do not delete, recreate, demote, overwrite assets on, or otherwise modify an already-public release without a separate explicit request for that exact operation. A rerun targeting a public tag must stop rather than modify that release.\n- Determine the next version from the latest **public** release plus one patch version, unless the user explicitly specifies a different version. Do not move an existing public tag to new code.\n- Report draft creation and build/test status accurately. Never describe a draft or queued workflow as a published release.\n\n## Subprojects (gitignored, referenced locally)\n\n`Motrix/`, `koodo-reader/`, `CloudServiceKit/`, `XbyVideoHub/`, `OpenCLI/`, `QuarkPan/`, `PikPakAPI/` — these are local-only and not part of the main repo build.\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/gaozhangmin/aliyunpan/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# AGENTS.md — BoxPlayer (aliyunpan)\n\n## “All Platforms” Scope\n\n- When the user says “all platforms” (`所有平台`), treat it as one request spanning all three repositories: `~/aliyunpan`, `~/BoxPlayer_Android`, and `~/XbyVideoHub`.\n- Implement the Electron/aliyunpan surface in `~/aliyunpan`; implement Android phone, tablet, and Android TV in `~/BoxPlayer_Android`; implement macOS, iOS/iPadOS, and tvOS in `~/XbyVideoHub`.\n- Inspect and modify each repository independently. Do not assume a change in one repository propagates to the other two.\n\n## Quick reference\n\n```bash\npnpm install          # install deps (pnpm only, never npm/yarn)\npnpm dev              # hot-reload Electron dev server\npnpm run build        # typecheck + bundle (vue-tsc --noEmit && vite build)\npnpm run test         # focused Vitest suite (not full repo)\npnpm run test:clouddrive-cli  # clouddrive-cli tests only\n```\n\n## Home Category Context Menus\n\n- Categories and independently placeable subcategories, including series, playlists, movie/TV child categories, genre, rating, score, and release-date values, use the same placement context-menu state machine.\n- An unplaced item shows “Add to Home” and “Add to Favorites”; both actions prompt for a user-defined display name.\n- After either add action succeeds, or when the item is initially visible on Home, the menu immediately switches to “Remove from Home” and “Rename Favorite.” The menu must not allow simultaneous Home and Favorites placement.\n- “Remove from Home” clears whichever placement contains the item. Renaming a favorite changes only its Favorites card title and does not rename the Home or sidebar title.\n\n## Package manager: pnpm only\n\nLockfile is `pnpm-lock.yaml`. `package-lock.json` and `yarn.lock` are in `.gitignore`.\nNever use `npm install` or `yarn`.\n\n## Node version\n\n`engines.node >= 22.12.0` in package.json. Electron 40 requires Node 22.12+ during install/build.\n\n## Build pipeline order matters\n\n`pnpm run build` runs **version bump → typecheck → vite bundle**. The version bump (`version.mjs`) auto-increments the patch version in package.json before every build. The build removes `dist/` and `release/` directories on start.\n\n`pnpm run build:electron` calls `build` first, then runs `electron-builder`.\n\nFor platform-specific packaging:\n```bash\npnpm run build:mac       # unsigned macOS\npnpm run build:mac:signed  # signed + notarized\npnpm run build:linux\npnpm run build:windows\npnpm run build:all       # cross-platform, sequential\n```\n\n## Sensitive config: generated secrets\n\nPrivate client IDs, client secrets, API keys, and private API URLs live outside git:\n\n```bash\npnpm run secrets:generate\n```\n\nLocal development reads them from `.env.local` and generates `src/secrets.generated.ts`. GitHub Actions reads the same keys from GitHub Secrets and runs `scripts/generate-secrets.mjs --mode=ci --strict` before building.\n\n`.env.local` and `src/secrets.generated.ts` are ignored and must never be committed. `src/config.ts` should import generated secrets or use placeholders, not contain real private values.\n\n## Architecture: Electron + Vue 3 + Vite\n\n| Directory | Purpose |\n|---|---|\n| `electron/main/` | Electron main process (entry: `electron/main/index.ts`) |\n| `electron/preload/` | Preload scripts |\n| `src/` | Vue 3 renderer (components, views, stores, API modules) |\n| `shared/` | Code shared between main + renderer |\n| `scripts/` | Build, CLI entry points, config management |\n| `clouddrive-cli/` | Standalone CLI package (published to npm as `clouddrive-cli`) |\n\nPath aliases (set in `tsconfig.json`, `vite.config.ts`, `vitest.config.ts`):\n- `@shared/*` → `shared/*`\n- `@main/*` → `electron/main/*`\n\nCloud provider API modules in `src/`: `aliapi/`, `cloudbaidu/`, `cloud123/`, `cloud115/`, `pikpak/`, `onedrive/`, `box/`, `dropbox/`, `quark/`, `cloud139/`, `cloud189/`.\n\n## GitHub Issue workflow\n\nWhen the user asks to handle GitHub Issues, first fetch the complete list of unfinished/open Issues in the requested repository. Review each Issue individually, identify its likely cause and affected code, and report the triage before changing code. Then implement fixes and run focused regression tests for each applicable Issue. Do not jump straight into a code change based only on the newest Issue or close an Issue before its fix is verified. If the repository or Issue access is unavailable, state that limitation rather than assuming the list is complete.\n\n## Testing: Vitest, Node environment, selective includes\n\n### Default app inspection: attach to the existing dev app\n\n- Unless the user explicitly asks to execute E2E tests, always connect to the app the user already started with `pnpm run dev` for inspection, reproduction, debugging, and UI verification.\n- Use the existing Electron CDP endpoint (normally `http://127.0.0.1:9223`; confirm the active endpoint). Playwright may attach with `chromium.connectOverCDP`; do not use `electron.launch`, spawn another Electron process, or start another `pnpm run dev` instance.\n- Preserve the running app's real user-data directory, accounts, settings, and playback state. Do not substitute an isolated/temporary profile or seed test data into the user's app.\n- Requests to review, investigate, reproduce, fix, or verify a bug are not explicit requests to run E2E tests. Do not automatically run `pretest:e2e`, `test:e2e`, or Playwright specs whose fixtures launch a separate app.\n- If the existing app or relevant window is unavailable, report that and ask the user to start/reopen it. Do not silently launch a replacement. Request approval before restarting the user's dev app when a main-process or native-module change requires it.\n- This rule takes precedence over the E2E workflow below. Record what was actually verified in the existing dev app; do not describe attached-session checks as production E2E acceptance. A pending E2E gate does not authorize launching another app.\n\n### Playwright acceptance gate when E2E execution is explicitly requested\n\nWhen the user explicitly asks to execute E2E tests, verify bug fixes through Playwright against an actually launched Electron application using the workflow below. Unit tests, type checks, source inspection, and merely starting `pnpm run dev` cannot replace this E2E gate.\n\n1. Add or update a Playwright regression test that reproduces the reported failure through the user-visible application flow.\n2. Build the production Electron entry with `pnpm run pretest:e2e`; do not test stale `dist/` output or an installed older BoxPlayer build.\n3. Run the focused Playwright regression test and record the exact command and result.\n4. For cloud-drive bugs, use the configured real account and exercise the real provider API. Do not skip the relevant real-account case or replace it with mocks.\n5. For platform-specific behavior that cannot execute on the current host, run Playwright on the target platform before calling the bug fixed. If that is unavailable, report the fix as unverified/blocked rather than complete.\n6. A failed, skipped, or unexecuted Playwright regression test blocks declaring the bug fixed and blocks release publication.\n\nKeep the regression test after the fix so the same bug cannot silently return.\n\nTests run in Node environment (not jsdom). The `vitest.config.ts` lists explicit test directories — not a glob over `**/*.test.ts`. Tests outside these paths are not picked up:\n\n- `electron/main/core/__tests__/`, `electron/main/aria/__tests__/`\n- `shared/__tests__/`, `scripts/__tests__/`\n- `src/down/motrix-integration/`, `src/media-server/__tests__/`\n- `src/utils/__tests__/`, `src/aliapi/__tests__/`\n- `src/pikpak/__tests__/`, `src/quark/__tests__/`\n- `src/dropbox/__tests__/`, `src/onedrive/__tests__/`, `src/box/__tests__/`\n- `clouddrive-cli/__tests__/`\n\nDefault `pnpm run test` runs only a subset (aria2 tests, motrix integration, a couple utils files).\n\nWhen adding tests in a new directory, update `vitest.config.ts`.\n\n## Pre-commit hooks\n\nDo not rely on pre-commit cleanup for secrets. Secret safety is handled by keeping real values in ignored/generated files and GitHub Secrets.\n\n## Formatting conventions\n\nFrom `.prettierrc`:\n- Single quotes, no semicolons\n- 260 printWidth (very wide)\n- No trailing commas\n- LF line endings\n- `sortAttributes: true` on HTML/Vue\n\n## TypeScript\n\n- `tsconfig.json` targets ESNext, moduleResolution node, strict mode, `@shared/*` and `@main/*` path aliases\n- Includes `src/` and `shared/`, excludes `shared/__tests__`\n- References `tsconfig.node.json` for Electron-side code\n\n## Provider Integration Checklist\n\nWhen adding a new cloud-drive provider, implement the following in order unless the user explicitly excludes a step. Do not stop after only wiring file listing. Sync/change-listening is not required by default.\n\n### 1. Account And Auth\n\n- Read the official OAuth/API documentation and prefer stable API versions.\n- Add `src/<provider>/auth.ts` with auth URL, authorization-code token exchange, and refresh token support.\n- Define `CLIENT_ID` / `CLIENT_SECRET` placeholder constants, defaulting to empty strings.\n- Add app key / secret fields to `.env.example`, `src/secrets.example.ts`, and `scripts/generate-secrets.mjs`.\n- Add the provider to `tokenfrom` in `src/user/userstore.ts`.\n- Wire login, token refresh, and drive loading in `src/user/userdal.ts`.\n- Add login entry points in `src/user/UserLogin.vue` and `src/user/UserInfo.vue`.\n\n### 2. Provider Detection And Drive Model\n\n- Add `is<Provider>User` in `src/aliapi/utils.ts`.\n- Update `GetDriveID` and `GetDriveType`, modeling third-party drives as a single-root drive.\n- Filter unsupported virtual directories in `src/pan/PanLeft.vue` and `src/pan/pantreestore.ts`.\n\n### 3. File List And Detail\n\n- Add `src/<provider>/dirfilelist.ts`.\n- Implement root listing, child directory pagination, and file detail.\n- Map official file models to `IAliGetFileModel`; at minimum fill `drive_id`, `file_id`, `parent_file_id`, `name`, `isDir`, `category`, `icon`, `size`, `time`, `thumbnail`, and `content_hash`.\n- Store provider-specific path, parent id, download URL, or similar metadata in `description`.\n- Wire root loading, directory listing, and search-listing branches in `src/pan/pandal.ts`.\n- Wire provider file detail in `src/aliapi/file.ts` `ApiFileInfo`.\n\n### 4. Download And Playback\n\n- Wire provider direct download URLs in `src/aliapi/file.ts` `ApiFileDownloadUrl`.\n- Third-party drives usually do not have Aliyun transcode APIs; `ApiVideoPreviewUrl` / `ApiAudioPreviewUrl` should return `暂无转码信息` or `undefined`, letting playback use the raw download URL.\n- Wire same-directory playlist loading in `src/layout/PageVideo.vue`, `src/utils/openfile.ts`, and `src/utils/playerhelper.ts`.\n- Confirm clicking provider videos does not call Aliyun APIs.\n\n### 5. Search\n\n- Add `src/<provider>/search.ts`.\n- Support keyword search.\n- If the existing UI uses special `file_id` values for search conditions, implement parse/build/filter helpers.\n- Wire search-directory branches in `src/pan/pandal.ts`.\n\n### 6. Thumbnails And Preview\n\n- Prefer thumbnails returned by list/detail APIs.\n- If the provider needs a separate thumbnail API, add `src/<provider>/thumbnail.ts`.\n- Fill `thumbnail` during file mapping so media library and file lists can use it directly.\n\n### 7. File Operations\n\n- Add `src/<provider>/filecmd.ts`.\n- Implement create folder, move to recycle bin, permanent delete, rename, move, and copy. Clearly report unsupported official capabilities.\n- Wire `ApiCreatNewForder`, `ApiTrashBatch`, `ApiDeleteBatch`, `ApiRenameBatch`, `ApiMoveBatch`, and `ApiCopyBatch` in `src/aliapi/filecmd.ts`.\n- Unsupported capabilities must not fall through to the Aliyun default branch.\n\n### 8. Sharing\n\n- Add `src/<provider>/share.ts` with share-link creation.\n- If the provider does not support password, expiration, or multi-file sharing, block it clearly in `src/aliapi/share.ts`.\n- Update context-menu and top-menu share visibility.\n\n### 9. Upload And New Files\n\n- Add or extend `src/<provider>/upload.ts`.\n- Implement in-memory upload for new text files.\n- Implement local-file upload worker support for ordinary file/folder uploads.\n- Implement large files using the provider-recommended session/chunk API.\n- Wire `src/aliapi/uploadmem.ts` and `src/workerpage/uploader.ts`.\n- Third-party drives do not support app custom encrypted/private uploads by default; hide those menu items.\n\n### 10. Media Library Scanning\n\n- Wire provider folder traversal in `src/utils/mediaScanner.ts`.\n- Wire provider subfolder entry in `src/components/MediaLibrary.vue`.\n- Show the provider name in media-library source labels.\n- Confirm scanning does not call Aliyun list APIs.\n\n### 11. Folder Picker Modal\n\n- Treat the provider as a single-root drive in `src/pan/topbtns/SelectPanDirModal.vue`.\n- Wire lazy child directory loading.\n- Move, copy, and save-location picker modals must browse provider directories.\n\n### 12. Menu Capability Boundaries\n\n- Update `src/pan/menus/FileRightMenu.vue`, `src/pan/menus/FileTopbtn.vue`, `src/pan/menus/DirLeftMenu.vue`, and `src/pan/menus/PanTopbtn.vue`.\n- Show common capabilities: download, share, rename, move to, copy to, delete, properties, scan media library, normal upload, and normal new file/folder.\n- Hide Aliyun-only capabilities: lucky bottle, fast transfer, favorite, transcode-related actions, mark encrypted, clear history, color labels, copy directory tree, encrypted/private new file, encrypted/private upload, and import share.\n\n### 13. Properties, Versions, And Recycle Bin\n\n- Wire provider file detail in `src/pan/topbtns/ShuXingModal.vue`.\n- If folder size has no official API, return 0 or hide it; do not call Aliyun folder-size APIs.\n- If the provider supports file versions, add `src/<provider>/revisions.ts` and expose version listing/restoration in properties.\n- If the provider supports recycle bin list/restore, add `src/<provider>/recyclebin.ts` and wire recycle-bin directory, restore, and permanent delete.\n- If the official API supports only some account types or needs higher permissions, record the limitation and keep it disabled by default.\n\n### 14. Tests\n\n- Add provider helper tests under `src/<provider>/__tests__/`.\n- Cover at least OAuth URL/token body, file-list path/body, model mapping, search path/body, share body/result mapping, file-operation body, upload session/chunk path, and version/recycle-bin path where applicable.\n- Update `vitest.config.ts` to include provider tests.\n\n### 15. Verification\n\n- Run provider unit tests.\n- Run `pnpm run build`.\n- If playback/media library is involved, verify provider videos use provider download URLs, same-directory playlists use provider list APIs, media-library scans use provider list APIs, and context menus do not expose unsupported capabilities.\n\n### Recommended File Structure\n\n```text\nsrc/<provider>/\n  auth.ts\n  dirfilelist.ts\n  filecmd.ts\n  search.ts\n  share.ts\n  upload.ts\n  revisions.ts       # optional\n  recyclebin.ts      # optional\n  thumbnail.ts       # optional\n  __tests__/\n```\n\n### Completion Criteria\n\n- Login and token refresh work.\n- The left tree shows root and folders.\n- File list opens root, subdirectories, and search results.\n- File detail, download, and video playback do not call the wrong provider API.\n- Context menus and top menus expose only supported capabilities.\n- Create folder, rename, move, copy, and delete call provider APIs.\n- Share, upload, and media-library scanning are wired or explicitly reported unsupported.\n- Provider unit tests pass.\n- `pnpm run build` passes.\n\n### Current Experience Notes\n\n- Dropbox and OneDrive should both be treated as single-root third-party drives.\n- Third-party drive video playback should prefer raw download URLs and must not reuse Aliyun transcode APIs.\n- Media-library scanning and same-directory playlists are the easiest provider branches to miss.\n- Auth pages should usually open in the system browser unless the provider explicitly requires an embedded flow.\n- App key / secret placeholder constants must be included in the generated-secrets flow, not committed as real values.\n\n## Cloud Download URL And Subtitle Contract\n\nTreat a cloud download URL and its request headers as one value. `ApiFileDownloadUrl` must return every provider-required header in `IDownloadUrl.headers`; callers must preserve those headers through playback, downloads, previews, and subtitles.\n\n| Provider | Download request requirements |\n|---|---|\n| Aliyun / Alipan | Signed CDN URL; Electron may add the Aliyun Referer/Origin for direct renderer requests. |\n| 115 | `Authorization: Bearer <account token>` and `DRIVE115_DOWN_AGENT`. The User-Agent used to consume the URL must match the one used to obtain it. Direct renderer playback must register URL-to-account auth context; never rely only on the currently selected account. |\n| Baidu | URL includes `access_token`; send `User-Agent: pan.baidu.com` and `Referer: https://pan.baidu.com/`. |\n| 123 | The returned signed download URL is self-authorizing; API Authorization is only for obtaining the URL. |\n| Quark | Account Cookie plus Quark download User-Agent, `Referer: https://pan.quark.cn/`, `Origin: https://pan.quark.cn`, and `x-urlp` when required by the OSS URL. |\n| 139 | `cloud139DownloadHeaders()`: provider User-Agent, Referer, and Origin. |\n| 189 | `cloud189DownloadHeaders()`: provider User-Agent and Referer. |\n| PikPak | Temporary download/stream URL returned by the provider. |\n| Dropbox / OneDrive | Temporary or pre-authenticated download URL returned by the provider. |\n| Box | Access token is encoded into the constructed download URL. |\n\nSubtitle rules:\n- Same-directory cloud subtitles must use `ApiFileDownloadUrl`; never fetch a guessed provider URL directly.\n- The web player and external players must use the subtitle-specific local proxy URL and pass `IDownloadUrl.headers` as `proxy_headers`.\n- The subtitle proxy must identify the account with `user_id` and the provider with `drive_id`; do not use a global/current-account token when an account-specific token is available.\n- Video streams remain direct URLs unless encryption requires the proxy. DLNA behavior is separate and must not be changed as part of subtitle or direct-play fixes.\n- Any provider download-header change requires regression coverage for both the video/download URL contract and same-directory subtitle loading.\n\n## clouddrive-cli\n\nStandalone CLI + MCP server for agent-driven cloud-drive operations. Docs: `clouddrive-cli/README.md`. The CLI supports 8 providers and has its own npm package (`clouddrive-cli`). Separate test command: `pnpm run test:clouddrive-cli`.\n\n## CI\n\nManual trigger only (`workflow_dispatch`) via `.github/workflows/release.yml`. Builds on `windows-latest` + `ubuntu-latest`, publishes draft GitHub Release. No automatic CI on push/PR.\n\n### Release ownership: drafts only\n\n- The human user owns the final publication of every GitHub Release. The agent and CI may prepare commits/tags, build and upload assets, and create/update **draft releases only** when requested.\n- Requests such as “发布 release”, “更新 release”, “重新提交代码更新 release”, or “继续发布” mean prepare/update a draft; they do **not** authorize making it public. The user publishes it manually in GitHub.\n- Never run `gh release edit --draft=false`, create a non-draft release, or enable automatic publication in a workflow or packaging configuration. Keep electron-builder `releaseType` set to `draft` and the workflow's final release update in draft state.\n- Do not delete, recreate, demote, overwrite assets on, or otherwise modify an already-public release without a separate explicit request for that exact operation. A rerun targeting a public tag must stop rather than modify that release.\n- Determine the next version from the latest **public** release plus one patch version, unless the user explicitly specifies a different version. Do not move an existing public tag to new code.\n- Report draft creation and build/test status accurately. Never describe a draft or queued workflow as a published release.\n\n## Subprojects (gitignored, referenced locally)\n\n`Motrix/`, `koodo-reader/`, `CloudServiceKit/`, `XbyVideoHub/`, `OpenCLI/`, `QuarkPan/`, `PikPakAPI/` — these are local-only and not part of the main repo build.\n","isInternal":false,"tokens":4669,"sizeBytes":20359},{"name":"SKILL.md","path":"clouddrive-cli/skill/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gaozhangmin/aliyunpan/HEAD/clouddrive-cli/skill/SKILL.md","title":"skill","category":"anthropic-skill","format":"markdown","content":"---\nname: clouddrive-cli\ndescription: Use when an agent needs to operate cloud-drive accounts through clouddrive-cli or clouddrive-mcp: discover logged-in accounts, inspect/list/walk/search cloud files, read local documents as context, generate or apply safe media rename/move/trash/upload/organize plans, and roll back supported operations.\nallowed-tools:\n  - Bash(clouddrive-cli:*)\n  - Bash(clouddrive-mcp:*)\n  - Read\n---\n\n# clouddrive-cli\n\n`clouddrive-cli` turns BoxPlayer cloud-drive accounts into a deterministic command surface for humans and AI agents. It supports Aliyun Drive, OneDrive, Dropbox, Box, 123Pan, 115 Drive, Baidu Netdisk, and PikPak.\n\nThis skill is the orientation layer. Discover the live CLI surface first, then choose the smallest safe command path for the user's goal.\n\n## The three pillars\n\n- **Account and provider discovery** — `auth list`, `settings show`, and `providers capabilities` tell you which accounts exist and which operations each provider supports.\n- **Cloud file operations** — `files list|walk|tree|stats|info|download|search|mkdir|rename-apply|move-apply|trash-apply` provide the stable boundary for reading and changing cloud files.\n- **Agent workflows** — `docs read`, `media *`, `upload *`, `organize *`, and `ops *` let agents combine local instructions, cloud inventory, dry-run plans, execution, and rollback.\n\n## Install and locate\n\n```bash\nwhich clouddrive-cli\nclouddrive-cli --help\nclouddrive-cli list --format json\n```\n\nIf the command is missing, ask the user to install it from BoxPlayer account settings or with `npm install -g clouddrive-cli`.\n\nThere are two install modes:\n\n- **BoxPlayer app mode** — the Electron app registers `clouddrive-cli` and exports logged-in account tokens.\n- **Standalone CLI mode** — install with npm and use `auth login` or `auth import-token` to add accounts.\n\n## Discover first\n\nDo not treat this file as the complete command registry. Start with live discovery:\n\n```bash\nclouddrive-cli list --format json\nclouddrive-cli schema commands\nclouddrive-cli auth list --format json\nclouddrive-cli settings show --format json\nclouddrive-cli providers capabilities --format json\n```\n\n`clouddrive-cli list --format json` is the source of truth for command metadata such as `access`, `requiresDryRun`, `destructive`, and `undoable`. `providers capabilities` is the source of truth for provider-specific support such as search, mkdir, move, rename, trash/delete, upload, recursive walk, path addressing, and file-id addressing.\n\n## Universal conventions\n\n| convention | meaning |\n|------------|---------|\n| `--format json` / `--json` | Agent-friendly JSON output. Prefer this by default. |\n| JSON errors | Failures return `{ ok: false, error: { code, message, exitCode } }` in JSON mode. Branch on `error.code`, not message text. |\n| dry-run first | Commands marked `requiresDryRun` must be previewed before execution. |\n| capability check | Before mkdir, move, rename, trash, upload, or organize apply, check `providers capabilities`. |\n| large output | Commands with `largeOutput: true` should use `--output <file.json>` so stdout stays a compact summary. |\n| rationale | Write commands accept `--rationale <reason>`; use it to preserve why the Agent is acting. |\n| no invented IDs | Get file IDs from `files list`, `files walk`, `files search`, `files tree`, or `files info`. |\n\nCommon error codes:\n\n| code | meaning | response |\n|------|---------|----------|\n| `AUTH_ERROR` | Missing/expired account or login failure. | Run `auth list`, `auth check`, `auth login`, or ask for token import. |\n| `PROVIDER_API_ERROR` | Provider returned an API/HTTP error. | Retry only if transient; otherwise record provider limitation. |\n| `UNSUPPORTED_CAPABILITY` | Provider or command capability is unavailable. | Stop or choose a supported fallback. |\n| `VALIDATION_ERROR` | Bad args, missing files, invalid plan, unknown operation. | Fix input before retrying. |\n\n## Read workflows\n\nUse bounded reads before large traversals:\n\n```bash\nclouddrive-cli files stats --provider aliyun --account default --file-id root --depth 2 --format json\nclouddrive-cli files stats --provider aliyun --account default --file-id root --output stats.json --format json\nclouddrive-cli files tree --provider aliyun --account default --file-id root --depth 1\nclouddrive-cli files list --provider aliyun --account default --file-id root --format json\nclouddrive-cli files list --provider aliyun --account default --file-id root --limit 100 --format json\nclouddrive-cli files list --provider aliyun --account default --file-id root --limit 100 --cursor <nextCursor> --format json\nclouddrive-cli files download --provider aliyun --account default --file-id <file-id> --output ./download.bin --format json\nclouddrive-cli files search --provider aliyun --account default --name \"movie\" --limit 50 --format json\n```\n\nRules of thumb:\n\n- Use `stats` or shallow `tree` to understand scale.\n- Use `search` for known keywords.\n- Use `walk` only after narrowing scope or when a full inventory is explicitly needed.\n- Avoid raw `files tree --json` and broad `walk` on large roots unless you will save and summarize the output locally.\n\nProvider root defaults when `--file-id` is omitted:\n\n| provider | default root |\n|----------|--------------|\n| aliyun | `root` |\n| cloud123 | `0` |\n| 115 | `0` |\n| baidu | `/` |\n| pikpak | `*` |\n| dropbox | empty string |\n| onedrive | `onedrive_root` |\n| box | `box_root` |\n\n## Write workflows\n\nNever apply a write plan first. The safe sequence is:\n\n1. Discover command metadata with `clouddrive-cli list --format json`.\n2. Check provider capability with `clouddrive-cli providers capabilities --format json`.\n3. Generate or read a plan.\n4. Run the dry-run or preview command.\n5. Show the user a concise summary of planned changes.\n6. Execute only after explicit user approval.\n7. Record the operation ID and rollback path when available.\n\nInclude `--rationale` on write commands, for example:\n\n```bash\nclouddrive-cli upload apply upload-plan.json --dry-run --rationale \"User asked to back up this folder\" --format json\n```\n\nCommon write previews:\n\n```bash\nclouddrive-cli files rename-apply rename-plan.json --current files.json --dry-run --format json\nclouddrive-cli files move-apply move-plan.json --dry-run --format json\nclouddrive-cli files trash-apply trash-plan.json --format json\nclouddrive-cli upload apply upload-plan.json --dry-run --format json\nclouddrive-cli organize apply organize-plan.json --dry-run --summary --format json\n```\n\nNotes:\n\n- `trash-apply` defaults to preview; execution requires `--apply`.\n- Rename and move operations are undoable through `ops undo`; trash is not.\n- Dropbox and Baidu move/trash plans may require path fields in addition to file IDs.\n- Upload planning exists for all providers. Real byte upload is wired for providers whose `providers capabilities` entry has `uploadFile: true` (`aliyun`, `cloud123`, `115`, `baidu`, `dropbox`, `onedrive`, `box` in this build); `pikpak` remains plan/dry-run only.\n\n## Media organization\n\nRecommended flow:\n\n```bash\nclouddrive-cli docs read ./rules.md --max-chars 50000 --format json\nclouddrive-cli docs read ./rules.pdf --pdf-format markdown --pdf-pages 1-3 --format json\nclouddrive-cli docs convert ./pdf-folder --output ./out --pdf-format json,html,pdf,markdown,tagged-pdf,text --format json\nclouddrive-cli files stats --provider aliyun --account default --file-id <folder-id> --depth 2 --format json\nclouddrive-cli files walk --provider aliyun --account default --file-id <folder-id> --output files.json --format json\nclouddrive-cli media match --input files.json --format json\n# Generate rename-plan.json yourself from rules, inventory, and match output.\nclouddrive-cli files rename-apply rename-plan.json --dry-run --format json\n```\n\n`media match` returns media fields under `match`, for example `{ fileId, name, match: { type, title, year, season, episode, confidence, jellyfin_name } }`.\n\nFor full-drive organization, treat broad plans as risky even if dry-run succeeds. Sample suspicious moves, check whether existing meaningful folders would be flattened into generic `Movies` or `TV Shows`, and prefer applying one folder/category at a time.\n\n## Rollback\n\n```bash\nclouddrive-cli ops list --format json\nclouddrive-cli ops show <operation-id> --format json\nclouddrive-cli ops undo <operation-id> --dry-run --format json\nclouddrive-cli ops undo <operation-id> --format json\n```\n\nAlways run `ops undo --dry-run` first. Only rename and move operations have CLI undo.\n\n## MCP\n\n`clouddrive-mcp` exposes the CLI manifest as MCP tools. Tool names and input schemas are generated from the same command manifest used by `clouddrive-cli list --format json`, so CLI/MCP discovery should stay aligned. Prefer direct CLI commands when:\n\n- You need file output redirection or plan files.\n- You are testing CLI behavior during skill/CLI iteration.\n\n## Known provider limitations\n\n- OneDrive `files search` may intermittently fail with Microsoft Graph `generalException` / HTTP 500. Use `files walk` plus local filtering as fallback.\n- PikPak `files search --name` may ignore the name query and return root items. Use `files walk` plus local filtering.\n- Baidu `files info` handles `filemetas` under either `list` or `info`, but `errno=12` can still indicate an API/token limitation. Fall back to `files walk` or `files search`.\n- 115 Open API folder fields may map folders as `type: file`. Confirm folder-ness by trying `files list --file-id <fileId>` before planning folder operations.\n\n## Don't\n\n- Don't paste this skill's command list into a plan; call `clouddrive-cli list --format json`.\n- Don't run non-dry-run writes without explicit user approval.\n- Don't assume root path tokens are portable across providers.\n- Don't continue after a structured JSON error without branching on `error.code`.\n- Don't emit huge raw inventories to the user; save, summarize, and sample.\n","isInternal":false,"tokens":2415,"sizeBytes":9930},{"name":"CLAUDE.md","path":"CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/gaozhangmin/aliyunpan/HEAD/CLAUDE.md","title":"Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Quick commands\n\n```bash\npnpm install          # pnpm only — never npm/yarn\npnpm dev              # hot-reload Electron dev server (Vite + vue-tsc)\npnpm run build        # version bump → typecheck → vite bundle\npnpm run build:electron  # full build + electron-builder packaging\npnpm run test         # focused Vitest suite (Node env, aria2 + motrix + utils)\npnpm run test:clouddrive-cli  # clouddrive-cli tests only\npnpm run build:mac    # unsigned macOS .dmg/.zip\npnpm run build:mac:signed  # signed + notarized macOS\npnpm run build:linux  # Linux .deb/.AppImage/.pacman\npnpm run build:windows  # Windows .exe/.zip\npnpm run build:all    # cross-platform sequentially\npnpm run config:clean     # blank API keys in src/config.ts (pre-commit hook)\npnpm run config:restore   # restore real keys after commit\n```\n\n## Architecture (Electron + Vue 3 + Vite)\n\n```\nelectron/main/       Electron main process (entry: electron/main/index.ts)\n  core/              Window lifecycle, IPC, auto-update, protocol, dialogs\n  aria/              Aria2c download engine (config, UPnP, runtime)\nelectron/preload/    Preload scripts (IPC bridge)\n\nsrc/                 Vue 3 renderer\n  aliapi/            Alibaba Cloud Drive SDK (files, share, user, etc.)\n  cloudbaidu/        Baidu Netdisk provider\n  cloud123/          123Pan provider\n  cloud115/          115Pan provider\n  pikpak/            PikPak provider\n  onedrive/          OneDrive provider\n  dropbox/           Dropbox provider\n  box/               Box provider\n  quark/             Quark provider\n  cloud139/          CMCloud provider\n  cloud189/          Tianyi Cloud provider\n  pan/               File manager UI (tree, menus, dialogs)\n  media-server/      Jellyfin/Emby/Plex integration\n  down/              Download manager + Aria2 integration\n  layout/            Main layout views (PageVideo, PageMusic, etc.)\n  module/            Feature modules (audioplayer, musicsdk, lyricplayer, theme)\n  store/             Pinia stores\n  components/        Shared Vue components\n  utils/             Shared utilities\n  user/              Auth, account management UI\n\nshared/              Code shared between main + renderer (constants, config keys, UA)\nscripts/             Build scripts, CLI entry points (clouddrive-cli.mjs, clouddrive-mcp.mjs)\nclouddrive-cli/      Standalone CLI + MCP server package (npm: clouddrive-cli)\n  core/              Command implementations, MCP server, upload planning\n  providers/         8 cloud-drive provider implementations\n  media/             Media matching + rename logic\n```\n\nPath aliases: `@shared/*` → `shared/*`, `@main/*` → `electron/main/*`\n\n## Key patterns\n\n- **pnpm only** — lockfile is `pnpm-lock.yaml`; `package-lock.json`/`yarn.lock` are gitignored\n- **Node ≥ 18**\n- **Pre-commit hooks** (`nano-staged.mjs`): prettier + eslint on JS/TS, stylelint + prettier on Vue/CSS, typecheck on changed `src/` files\n- **Formatting**: single quotes, no semicolons, 260 printWidth, no trailing commas, LF, `sortAttributes: true` in Vue\n- **TypeScript**: strict mode, ESNext target, node moduleResolution\n- **Sensitive config**: `scripts/clean-config.js` blanks API keys pre-commit; restore with `pnpm run config:restore`\n- **Vitest**: Node environment only, explicit test directory list in `vitest.config.ts` (not glob patterns). Add new test dirs to config.\n- **CI**: Manual trigger only via `.github/workflows/release.yml`, publishes draft GitHub Release\n\n## clouddrive-cli (AI agent integration)\n\nStandalone CLI + MCP server for agent-driven cloud-drive operations. Supports 8 providers: aliyun, cloud123, 115, baidu, pikpak, onedrive, box, dropbox.\n\nKey bins: `clouddrive-cli` (CLI), `clouddrive-mcp` (MCP server). Both point to `scripts/clouddrive-cli.mjs` and `scripts/clouddrive-mcp.mjs` respectively.\n\nAgent rules when using the CLI:\n1. Discover commands first: `clouddrive-cli list --format json`\n2. Check capabilities: `clouddrive-cli providers capabilities --format json`\n3. Always dry-run before destructive ops\n4. Never invent file IDs — they must come from `files list`/`walk`/`search`/`tree`\n5. Use `--output <file.json>` for large results\n\n## Adding a new cloud-drive provider\n\nFollow the 15-step checklist in `AGENT.md` (OAuth → provider detection → file listing → download/playback → search → thumbnails → file operations → sharing → upload → media scan → folder picker → menu boundaries → properties/recycle bin → tests → verification). The checklist is authoritative — do not ship a provider that only does file listing.\n","isInternal":false,"tokens":1173,"sizeBytes":4676}],"systemPromptSnippet":"<yakaai_skills repo=\"gaozhangmin/aliyunpan\">\n<!-- File: AGENTS.md (Tokens: ~4669 | Category: root-instruction) -->\n# AGENTS.md — BoxPlayer (aliyunpan)\n\n## “All Platforms” Scope\n\n- When the user says “all platforms” (`所有平台`), treat it as one request spanning all three repositories: `~/aliyunpan`, `~/BoxPlayer_Android`, and `~/XbyVideoHub`.\n- Implement the Electron/aliyunpan surface in `~/aliyunpan`; implement Android phone, tablet, and Android TV in `~/BoxPlayer_Android`; implement macOS, iOS/iPadOS, and tvOS in `~/XbyVideoHub`.\n- Inspect and modify each repository independently. Do not assume a change in one repository propagates to the other two.\n\n## Quick reference\n\n```bash\npnpm install          # install deps (pnpm only, never npm/yarn)\npnpm dev              # hot-reload Electron dev server\npnpm run build        # typecheck + bundle (vue-tsc --noEmit && vite build)\npnpm run test         # focused Vitest suite (not full repo)\npnpm run test:clouddrive-cli  # clouddrive-cli tests only\n```\n\n## Home Category Context Menus\n\n- Categories and independently placeable subcategories, including series, playlists, movie/TV child categories, genre, rating, score, and release-date values, use the same placement context-menu state machine.\n- An unplaced item shows “Add to Home” and “Add to Favorites”; both actions prompt for a user-defined display name.\n- After either add action succeeds, or when the item is initially visible on Home, the menu immediately switches to “Remove from Home” and “Rename Favorite.” The menu must not allow simultaneous Home and Favorites placement.\n- “Remove from Home” clears whichever placement contains the item. Renaming a favorite changes only its Favorites card title and does not rename the Home or sidebar title.\n\n## Package manager: pnpm only\n\nLockfile is `pnpm-lock.yaml`. `package-lock.json` and `yarn.lock` are in `.gitignore`.\nNever use `npm install` or `yarn`.\n\n## Node version\n\n`engines.node >= 22.12.0` in package.json. Electron 40 requires Node 22.12+ during install/build.\n\n## Build pipeline order matters\n\n`pnpm run build` runs **version bump → typecheck → vite bundle**. The version bump (`version.mjs`) auto-increments the patch version in package.json before every build. The build removes `dist/` and `release/` directories on start.\n\n`pnpm run build:electron` calls `build` first, then runs `electron-builder`.\n\nFor platform-specific packaging:\n```bash\npnpm run build:mac       # unsigned macOS\npnpm run build:mac:signed  # signed + notarized\npnpm run build:linux\npnpm run build:windows\npnpm run build:all       # cross-platform, sequential\n```\n\n## Sensitive config: generated secrets\n\nPrivate client IDs, client secrets, API keys, and private API URLs live outside git:\n\n```bash\npnpm run secrets:generate\n```\n\nLocal development reads them from `.env.local` and generates `src/secrets.generated.ts`. GitHub Actions reads the same keys from GitHub Secrets and runs `scripts/generate-secrets.mjs --mode=ci --strict` before building.\n\n`.env.local` and `src/secrets.generated.ts` are ignored and must never be committed. `src/config.ts` should import generated secrets or use placeholders, not contain real private values.\n\n## Architecture: Electron + Vue 3 + Vite\n\n| Directory | Purpose |\n|---|---|\n| `electron/main/` | Electron main process (entry: `electron/main/index.ts`) |\n| `electron/preload/` | Preload scripts |\n| `src/` | Vue 3 renderer (components, views, stores, API modules) |\n| `shared/` | Code shared between main + renderer |\n| `scripts/` | Build, CLI entry points, config management |\n| `clouddrive-cli/` | Standalone CLI package (published to npm as `clouddrive-cli`) |\n\nPath aliases (set in `tsconfig.json`, `vite.config.ts`, `vitest.config.ts`):\n- `@shared/*` → `shared/*`\n- `@main/*` → `electron/main/*`\n\nCloud provider API modules in `src/`: `aliapi/`, `cloudbaidu/`, `cloud123/`, `cloud115/`, `pikpak/`, `onedrive/`, `box/`, `dropbox/`, `quark/`, `cloud139/`, `cloud189/`.\n\n## GitHub Issue workflow\n\nWhen the user asks to handle GitHub Issues, first fetch the complete list of unfinished/open Issues in the requested repository. Review each Issue individually, identify its likely cause and affected code, and report the triage before changing code. Then implement fixes and run focused regression tests for each applicable Issue. Do not jump straight into a code change based only on the newest Issue or close an Issue before its fix is verified. If the repository or Issue access is unavailable, state that limitation rather than assuming the list is complete.\n\n## Testing: Vitest, Node environment, selective includes\n\n### Default app inspection: attach to the existing dev app\n\n- Unless the user explicitly asks to execute E2E tests, always connect to the app the user already started with `pnpm run dev` for inspection, reproduction, debugging, and UI verification.\n- Use the existing Electron CDP endpoint (normally `http://127.0.0.1:9223`; confirm the active endpoint). Playwright may attach with `chromium.connectOverCDP`; do not use `electron.launch`, spawn another Electron process, or start another `pnpm run dev` instance.\n- Preserve the running app's real user-data directory, accounts, settings, and playback state. Do not substitute an isolated/temporary profile or seed test data into the user's app.\n- Requests to review, investigate, reproduce, fix, or verify a bug are not explicit requests to run E2E tests. Do not automatically run `pretest:e2e`, `test:e2e`, or Playwright specs whose fixtures launch a separate app.\n- If the existing app or relevant window is unavailable, report that and ask the user to start/reopen it. Do not silently launch a replacement. Request approval before restarting the user's dev app when a main-process or native-module change requires it.\n- This rule takes precedence over the E2E workflow below. Record what was actually verified in the existing dev app; do not describe attached-session checks as production E2E acceptance. A pending E2E gate does not authorize launching another app.\n\n### Playwright acceptance gate when E2E execution is explicitly requested\n\nWhen the user explicitly asks to execute E2E tests, verify bug fixes through Playwright against an actually launched Electron application using the workflow below. Unit tests, type checks, source inspection, and merely starting `pnpm run dev` cannot replace this E2E gate.\n\n1. Add or update a Playwright regression test that reproduces the reported failure through the user-visible application flow.\n2. Build the production Electron entry with `pnpm run pretest:e2e`; do not test stale `dist/` output or an installed older BoxPlayer build.\n3. Run the focused Playwright regression test and record the exact command and result.\n4. For cloud-drive bugs, use the configured real account and exercise the real provider API. Do not skip the relevant real-account case or replace it with mocks.\n5. For platform-specific behavior that cannot execute on the current host, run Playwright on the target platform before calling the bug fixed. If that is unavailable, report the fix as unverified/blocked rather than complete.\n6. A failed, skipped, or unexecuted Playwright regression test blocks declaring the bug fixed and blocks release publication.\n\nKeep the regression test after the fix so the same bug cannot silently return.\n\nTests run in Node environment (not jsdom). The `vitest.config.ts` lists explicit test directories — not a glob over `**/*.test.ts`. Tests outside these paths are not picked up:\n\n- `electron/main/core/__tests__/`, `electron/main/aria/__tests__/`\n- `shared/__tests__/`, `scripts/__tests__/`\n- `src/down/motrix-integration/`, `src/media-server/__tests__/`\n- `src/utils/__tests__/`, `src/aliapi/__tests__/`\n- `src/pikpak/__tests__/`, `src/quark/__tests__/`\n- `src/dropbox/__tests__/`, `src/onedrive/__tests__/`, `src/box/__tests__/`\n- `clouddrive-cli/__tests__/`\n\nDefault `pnpm run test` runs only a subset (aria2 tests, motrix integration, a couple utils files).\n\nWhen adding tests in a new directory, update `vitest.config.ts`.\n\n## Pre-commit hooks\n\nDo not rely on pre-commit cleanup for secrets. Secret safety is handled by keeping real values in ignored/generated files and GitHub Secrets.\n\n## Formatting conventions\n\nFrom `.prettierrc`:\n- Single quotes, no semicolons\n- 260 printWidth (very wide)\n- No trailing commas\n- LF line endings\n- `sortAttributes: true` on HTML/Vue\n\n## TypeScript\n\n- `tsconfig.json` targets ESNext, moduleResolution node, strict mode, `@shared/*` and `@main/*` path aliases\n- Includes `src/` and `shared/`, excludes `shared/__tests__`\n- References `tsconfig.node.json` for Electron-side code\n\n## Provider Integration Checklist\n\nWhen adding a new cloud-drive provider, implement the following in order unless the user explicitly excludes a step. Do not stop after only wiring file listing. Sync/change-listening is not required by default.\n\n### 1. Account And Auth\n\n- Read the official OAuth/API documentation and prefer stable API versions.\n- Add `src/<provider>/auth.ts` with auth URL, authorization-code token exchange, and refresh token support.\n- Define `CLIENT_ID` / `CLIENT_SECRET` placeholder constants, defaulting to empty strings.\n- Add app key / secret fields to `.env.example`, `src/secrets.example.ts`, and `scripts/generate-secrets.mjs`.\n- Add the provider to `tokenfrom` in `src/user/userstore.ts`.\n- Wire login, token refresh, and drive loading in `src/user/userdal.ts`.\n- Add login entry points in `src/user/UserLogin.vue` and `src/user/UserInfo.vue`.\n\n### 2. Provider Detection And Drive Model\n\n- Add `is<Provider>User` in `src/aliapi/utils.ts`.\n- Update `GetDriveID` and `GetDriveType`, modeling third-party drives as a single-root drive.\n- Filter unsupported virtual directories in `src/pan/PanLeft.vue` and `src/pan/pantreestore.ts`.\n\n### 3. File List And Detail\n\n- Add `src/<provider>/dirfilelist.ts`.\n- Implement root listing, child directory pagination, and file detail.\n- Map official file models to `IAliGetFileModel`; at minimum fill `drive_id`, `file_id`, `parent_file_id`, `name`, `isDir`, `category`, `icon`, `size`, `time`, `thumbnail`, and `content_hash`.\n- Store provider-specific path, parent id, download URL, or similar metadata in `description`.\n- Wire root loading, directory listing, and search-listing branches in `src/pan/pandal.ts`.\n- Wire provider file detail in `src/aliapi/file.ts` `ApiFileInfo`.\n\n### 4. Download And Playback\n\n- Wire provider direct download URLs in `src/aliapi/file.ts` `ApiFileDownloadUrl`.\n- Third-party drives usually do not have Aliyun transcode APIs; `ApiVideoPreviewUrl` / `ApiAudioPreviewUrl` should return `暂无转码信息` or `undefined`, letting playback use the raw download URL.\n- Wire same-directory playlist loading in `src/layout/PageVideo.vue`, `src/utils/openfile.ts`, and `src/utils/playerhelper.ts`.\n- Confirm clicking provider videos does not call Aliyun APIs.\n\n### 5. Search\n\n- Add `src/<provider>/search.ts`.\n- Support keyword search.\n- If the existing UI uses special `file_id` values for search conditions, implement parse/build/filter helpers.\n- Wire search-directory branches in `src/pan/pandal.ts`.\n\n### 6. Thumbnails And Preview\n\n- Prefer thumbnails returned by list/detail APIs.\n- If the provider needs a separate thumbnail API, add `src/<provider>/thumbnail.ts`.\n- Fill `thumbnail` during file mapping so media library and file lists can use it directly.\n\n### 7. File Operations\n\n- Add `src/<provider>/filecmd.ts`.\n- Implement create folder, move to recycle bin, permanent delete, rename, move, and copy. Clearly report unsupported official capabilities.\n- Wire `ApiCreatNewForder`, `ApiTrashBatch`, `ApiDeleteBatch`, `ApiRenameBatch`, `ApiMoveBatch`, and `ApiCopyBatch` in `src/aliapi/filecmd.ts`.\n- Unsupported capabilities must not fall through to the Aliyun default branch.\n\n### 8. Sharing\n\n- Add `src/<provider>/share.ts` with share-link creation.\n- If the provider does not support password, expiration, or multi-file sharing, block it clearly in `src/aliapi/share.ts`.\n- Update context-menu and top-menu share visibility.\n\n### 9. Upload And New Files\n\n- Add or extend `src/<provider>/upload.ts`.\n- Implement in-memory upload for new text files.\n- Implement local-file upload worker support for ordinary file/folder uploads.\n- Implement large files using the provider-recommended session/chunk API.\n- Wire `src/aliapi/uploadmem.ts` and `src/workerpage/uploader.ts`.\n- Third-party drives do not support app custom encrypted/private uploads by default; hide those menu items.\n\n### 10. Media Library Scanning\n\n- Wire provider folder traversal in `src/utils/mediaScanner.ts`.\n- Wire provider subfolder entry in `src/components/MediaLibrary.vue`.\n- Show the provider name in media-library source labels.\n- Confirm scanning does not call Aliyun list APIs.\n\n### 11. Folder Picker Modal\n\n- Treat the provider as a single-root drive in `src/pan/topbtns/SelectPanDirModal.vue`.\n- Wire lazy child directory loading.\n- Move, copy, and save-location picker modals must browse provider directories.\n\n### 12. Menu Capability Boundaries\n\n- Update `src/pan/menus/FileRightMenu.vue`, `src/pan/menus/FileTopbtn.vue`, `src/pan/menus/DirLeftMenu.vue`, and `src/pan/menus/PanTopbtn.vue`.\n- Show common capabilities: download, share, rename, move to, copy to, delete, properties, scan media library, normal upload, and normal new file/folder.\n- Hide Aliyun-only capabilities: lucky bottle, fast transfer, favorite, transcode-related actions, mark encrypted, clear history, color labels, copy directory tree, encrypted/private new file, encrypted/private upload, and import share.\n\n### 13. Properties, Versions, And Recycle Bin\n\n- Wire provider file detail in `src/pan/topbtns/ShuXingModal.vue`.\n- If folder size has no official API, return 0 or hide it; do not call Aliyun folder-size APIs.\n- If the provider supports file versions, add `src/<provider>/revisions.ts` and expose version listing/restoration in properties.\n- If the provider supports recycle bin list/restore, add `src/<provider>/recyclebin.ts` and wire recycle-bin directory, restore, and permanent delete.\n- If the official API supports only some account types or needs higher permissions, record the limitation and keep it disabled by default.\n\n### 14. Tests\n\n- Add provider helper tests under `src/<provider>/__tests__/`.\n- Cover at least OAuth URL/token body, file-list path/body, model mapping, search path/body, share body/result mapping, file-operation body, upload session/chunk path, and version/recycle-bin path where applicable.\n- Update `vitest.config.ts` to include provider tests.\n\n### 15. Verification\n\n- Run provider unit tests.\n- Run `pnpm run build`.\n- If playback/media library is involved, verify provider videos use provider download URLs, same-directory playlists use provider list APIs, media-library scans use provider list APIs, and context menus do not expose unsupported capabilities.\n\n### Recommended File Structure\n\n```text\nsrc/<provider>/\n  auth.ts\n  dirfilelist.ts\n  filecmd.ts\n  search.ts\n  share.ts\n  upload.ts\n  revisions.ts       # optional\n  recyclebin.ts      # optional\n  thumbnail.ts       # optional\n  __tests__/\n```\n\n### Completion Criteria\n\n- Login and token refresh work.\n- The left tree shows root and folders.\n- File list opens root, subdirectories, and search results.\n- File detail, download, and video playback do not call the wrong provider API.\n- Context menus and top menus expose only supported capabilities.\n- Create folder, rename, move, copy, and delete call provider APIs.\n- Share, upload, and media-library scanning are wired or explicitly reported unsupported.\n- Provider unit tests pass.\n- `pnpm run build` passes.\n\n### Current Experience Notes\n\n- Dropbox and OneDrive should both be treated as single-root third-party drives.\n- Third-party drive video playback should prefer raw download URLs and must not reuse Aliyun transcode APIs.\n- Media-library scanning and same-directory playlists are the easiest provider branches to miss.\n- Auth pages should usually open in the system browser unless the provider explicitly requires an embedded flow.\n- App key / secret placeholder constants must be included in the generated-secrets flow, not committed as real values.\n\n## Cloud Download URL And Subtitle Contract\n\nTreat a cloud download URL and its request headers as one value. `ApiFileDownloadUrl` must return every provider-required header in `IDownloadUrl.headers`; callers must preserve those headers through playback, downloads, previews, and subtitles.\n\n| Provider | Download request requirements |\n|---|---|\n| Aliyun / Alipan | Signed CDN URL; Electron may add the Aliyun Referer/Origin for direct renderer requests. |\n| 115 | `Authorization: Bearer <account token>` and `DRIVE115_DOWN_AGENT`. The User-Agent used to consume the URL must match the one used to obtain it. Direct renderer playback must register URL-to-account auth context; never rely only on the currently selected account. |\n| Baidu | URL includes `access_token`; send `User-Agent: pan.baidu.com` and `Referer: https://pan.baidu.com/`. |\n| 123 | The returned signed download URL is self-authorizing; API Authorization is only for obtaining the URL. |\n| Quark | Account Cookie plus Quark download User-Agent, `Referer: https://pan.quark.cn/`, `Origin: https://pan.quark.cn`, and `x-urlp` when required by the OSS URL. |\n| 139 | `cloud139DownloadHeaders()`: provider User-Agent, Referer, and Origin. |\n| 189 | `cloud189DownloadHeaders()`: provider User-Agent and Referer. |\n| PikPak | Temporary download/stream URL returned by the provider. |\n| Dropbox / OneDrive | Temporary or pre-authenticated download URL returned by the provider. |\n| Box | Access token is encoded into the constructed download URL. |\n\nSubtitle rules:\n- Same-directory cloud subtitles must use `ApiFileDownloadUrl`; never fetch a guessed provider URL directly.\n- The web player and external players must use the subtitle-specific local proxy URL and pass `IDownloadUrl.headers` as `proxy_headers`.\n- The subtitle proxy must identify the account with `user_id` and the provider with `drive_id`; do not use a global/current-account token when an account-specific token is available.\n- Video streams remain direct URLs unless encryption requires the proxy. DLNA behavior is separate and must not be changed as part of subtitle or direct-play fixes.\n- Any provider download-header change requires regression coverage for both the video/download URL contract and same-directory subtitle loading.\n\n## clouddrive-cli\n\nStandalone CLI + MCP server for agent-driven cloud-drive operations. Docs: `clouddrive-cli/README.md`. The CLI supports 8 providers and has its own npm package (`clouddrive-cli`). Separate test command: `pnpm run test:clouddrive-cli`.\n\n## CI\n\nManual trigger only (`workflow_dispatch`) via `.github/workflows/release.yml`. Builds on `windows-latest` + `ubuntu-latest`, publishes draft GitHub Release. No automatic CI on push/PR.\n\n### Release ownership: drafts only\n\n- The human user owns the final publication of every GitHub Release. The agent and CI may prepare commits/tags, build and upload assets, and create/update **draft releases only** when requested.\n- Requests such as “发布 release”, “更新 release”, “重新提交代码更新 release”, or “继续发布” mean prepare/update a draft; they do **not** authorize making it public. The user publishes it manually in GitHub.\n- Never run `gh release edit --draft=false`, create a non-draft release, or enable automatic publication in a workflow or packaging configuration. Keep electron-builder `releaseType` set to `draft` and the workflow's final release update in draft state.\n- Do not delete, recreate, demote, overwrite assets on, or otherwise modify an already-public release without a separate explicit request for that exact operation. A rerun targeting a public tag must stop rather than modify that release.\n- Determine the next version from the latest **public** release plus one patch version, unless the user explicitly specifies a different version. Do not move an existing public tag to new code.\n- Report draft creation and build/test status accurately. Never describe a draft or queued workflow as a published release.\n\n## Subprojects (gitignored, referenced locally)\n\n`Motrix/`, `koodo-reader/`, `CloudServiceKit/`, `XbyVideoHub/`, `OpenCLI/`, `QuarkPan/`, `PikPakAPI/` — these are local-only and not part of the main repo build.\n\n<!-- File: clouddrive-cli/skill/SKILL.md (Tokens: ~2415 | Category: anthropic-skill) -->\n---\nname: clouddrive-cli\ndescription: Use when an agent needs to operate cloud-drive accounts through clouddrive-cli or clouddrive-mcp: discover logged-in accounts, inspect/list/walk/search cloud files, read local documents as context, generate or apply safe media rename/move/trash/upload/organize plans, and roll back supported operations.\nallowed-tools:\n  - Bash(clouddrive-cli:*)\n  - Bash(clouddrive-mcp:*)\n  - Read\n---\n\n# clouddrive-cli\n\n`clouddrive-cli` turns BoxPlayer cloud-drive accounts into a deterministic command surface for humans and AI agents. It supports Aliyun Drive, OneDrive, Dropbox, Box, 123Pan, 115 Drive, Baidu Netdisk, and PikPak.\n\nThis skill is the orientation layer. Discover the live CLI surface first, then choose the smallest safe command path for the user's goal.\n\n## The three pillars\n\n- **Account and provider discovery** — `auth list`, `settings show`, and `providers capabilities` tell you which accounts exist and which operations each provider supports.\n- **Cloud file operations** — `files list|walk|tree|stats|info|download|search|mkdir|rename-apply|move-apply|trash-apply` provide the stable boundary for reading and changing cloud files.\n- **Agent workflows** — `docs read`, `media *`, `upload *`, `organize *`, and `ops *` let agents combine local instructions, cloud inventory, dry-run plans, execution, and rollback.\n\n## Install and locate\n\n```bash\nwhich clouddrive-cli\nclouddrive-cli --help\nclouddrive-cli list --format json\n```\n\nIf the command is missing, ask the user to install it from BoxPlayer account settings or with `npm install -g clouddrive-cli`.\n\nThere are two install modes:\n\n- **BoxPlayer app mode** — the Electron app registers `clouddrive-cli` and exports logged-in account tokens.\n- **Standalone CLI mode** — install with npm and use `auth login` or `auth import-token` to add accounts.\n\n## Discover first\n\nDo not treat this file as the complete command registry. Start with live discovery:\n\n```bash\nclouddrive-cli list --format json\nclouddrive-cli schema commands\nclouddrive-cli auth list --format json\nclouddrive-cli settings show --format json\nclouddrive-cli providers capabilities --format json\n```\n\n`clouddrive-cli list --format json` is the source of truth for command metadata such as `access`, `requiresDryRun`, `destructive`, and `undoable`. `providers capabilities` is the source of truth for provider-specific support such as search, mkdir, move, rename, trash/delete, upload, recursive walk, path addressing, and file-id addressing.\n\n## Universal conventions\n\n| convention | meaning |\n|------------|---------|\n| `--format json` / `--json` | Agent-friendly JSON output. Prefer this by default. |\n| JSON errors | Failures return `{ ok: false, error: { code, message, exitCode } }` in JSON mode. Branch on `error.code`, not message text. |\n| dry-run first | Commands marked `requiresDryRun` must be previewed before execution. |\n| capability check | Before mkdir, move, rename, trash, upload, or organize apply, check `providers capabilities`. |\n| large output | Commands with `largeOutput: true` should use `--output <file.json>` so stdout stays a compact summary. |\n| rationale | Write commands accept `--rationale <reason>`; use it to preserve why the Agent is acting. |\n| no invented IDs | Get file IDs from `files list`, `files walk`, `files search`, `files tree`, or `files info`. |\n\nCommon error codes:\n\n| code | meaning | response |\n|------|---------|----------|\n| `AUTH_ERROR` | Missing/expired account or login failure. | Run `auth list`, `auth check`, `auth login`, or ask for token import. |\n| `PROVIDER_API_ERROR` | Provider returned an API/HTTP error. | Retry only if transient; otherwise record provider limitation. |\n| `UNSUPPORTED_CAPABILITY` | Provider or command capability is unavailable. | Stop or choose a supported fallback. |\n| `VALIDATION_ERROR` | Bad args, missing files, invalid plan, unknown operation. | Fix input before retrying. |\n\n## Read workflows\n\nUse bounded reads before large traversals:\n\n```bash\nclouddrive-cli files stats --provider aliyun --account default --file-id root --depth 2 --format json\nclouddrive-cli files stats --provider aliyun --account default --file-id root --output stats.json --format json\nclouddrive-cli files tree --provider aliyun --account default --file-id root --depth 1\nclouddrive-cli files list --provider aliyun --account default --file-id root --format json\nclouddrive-cli files list --provider aliyun --account default --file-id root --limit 100 --format json\nclouddrive-cli files list --provider aliyun --account default --file-id root --limit 100 --cursor <nextCursor> --format json\nclouddrive-cli files download --provider aliyun --account default --file-id <file-id> --output ./download.bin --format json\nclouddrive-cli files search --provider aliyun --account default --name \"movie\" --limit 50 --format json\n```\n\nRules of thumb:\n\n- Use `stats` or shallow `tree` to understand scale.\n- Use `search` for known keywords.\n- Use `walk` only after narrowing scope or when a full inventory is explicitly needed.\n- Avoid raw `files tree --json` and broad `walk` on large roots unless you will save and summarize the output locally.\n\nProvider root defaults when `--file-id` is omitted:\n\n| provider | default root |\n|----------|--------------|\n| aliyun | `root` |\n| cloud123 | `0` |\n| 115 | `0` |\n| baidu | `/` |\n| pikpak | `*` |\n| dropbox | empty string |\n| onedrive | `onedrive_root` |\n| box | `box_root` |\n\n## Write workflows\n\nNever apply a write plan first. The safe sequence is:\n\n1. Discover command metadata with `clouddrive-cli list --format json`.\n2. Check provider capability with `clouddrive-cli providers capabilities --format json`.\n3. Generate or read a plan.\n4. Run the dry-run or preview command.\n5. Show the user a concise summary of planned changes.\n6. Execute only after explicit user approval.\n7. Record the operation ID and rollback path when available.\n\nInclude `--rationale` on write commands, for example:\n\n```bash\nclouddrive-cli upload apply upload-plan.json --dry-run --rationale \"User asked to back up this folder\" --format json\n```\n\nCommon write previews:\n\n```bash\nclouddrive-cli files rename-apply rename-plan.json --current files.json --dry-run --format json\nclouddrive-cli files move-apply move-plan.json --dry-run --format json\nclouddrive-cli files trash-apply trash-plan.json --format json\nclouddrive-cli upload apply upload-plan.json --dry-run --format json\nclouddrive-cli organize apply organize-plan.json --dry-run --summary --format json\n```\n\nNotes:\n\n- `trash-apply` defaults to preview; execution requires `--apply`.\n- Rename and move operations are undoable through `ops undo`; trash is not.\n- Dropbox and Baidu move/trash plans may require path fields in addition to file IDs.\n- Upload planning exists for all providers. Real byte upload is wired for providers whose `providers capabilities` entry has `uploadFile: true` (`aliyun`, `cloud123`, `115`, `baidu`, `dropbox`, `onedrive`, `box` in this build); `pikpak` remains plan/dry-run only.\n\n## Media organization\n\nRecommended flow:\n\n```bash\nclouddrive-cli docs read ./rules.md --max-chars 50000 --format json\nclouddrive-cli docs read ./rules.pdf --pdf-format markdown --pdf-pages 1-3 --format json\nclouddrive-cli docs convert ./pdf-folder --output ./out --pdf-format json,html,pdf,markdown,tagged-pdf,text --format json\nclouddrive-cli files stats --provider aliyun --account default --file-id <folder-id> --depth 2 --format json\nclouddrive-cli files walk --provider aliyun --account default --file-id <folder-id> --output files.json --format json\nclouddrive-cli media match --input files.json --format json\n# Generate rename-plan.json yourself from rules, inventory, and match output.\nclouddrive-cli files rename-apply rename-plan.json --dry-run --format json\n```\n\n`media match` returns media fields under `match`, for example `{ fileId, name, match: { type, title, year, season, episode, confidence, jellyfin_name } }`.\n\nFor full-drive organization, treat broad plans as risky even if dry-run succeeds. Sample suspicious moves, check whether existing meaningful folders would be flattened into generic `Movies` or `TV Shows`, and prefer applying one folder/category at a time.\n\n## Rollback\n\n```bash\nclouddrive-cli ops list --format json\nclouddrive-cli ops show <operation-id> --format json\nclouddrive-cli ops undo <operation-id> --dry-run --format json\nclouddrive-cli ops undo <operation-id> --format json\n```\n\nAlways run `ops undo --dry-run` first. Only rename and move operations have CLI undo.\n\n## MCP\n\n`clouddrive-mcp` exposes the CLI manifest as MCP tools. Tool names and input schemas are generated from the same command manifest used by `clouddrive-cli list --format json`, so CLI/MCP discovery should stay aligned. Prefer direct CLI commands when:\n\n- You need file output redirection or plan files.\n- You are testing CLI behavior during skill/CLI iteration.\n\n## Known provider limitations\n\n- OneDrive `files search` may intermittently fail with Microsoft Graph `generalException` / HTTP 500. Use `files walk` plus local filtering as fallback.\n- PikPak `files search --name` may ignore the name query and return root items. Use `files walk` plus local filtering.\n- Baidu `files info` handles `filemetas` under either `list` or `info`, but `errno=12` can still indicate an API/token limitation. Fall back to `files walk` or `files search`.\n- 115 Open API folder fields may map folders as `type: file`. Confirm folder-ness by trying `files list --file-id <fileId>` before planning folder operations.\n\n## Don't\n\n- Don't paste this skill's command list into a plan; call `clouddrive-cli list --format json`.\n- Don't run non-dry-run writes without explicit user approval.\n- Don't assume root path tokens are portable across providers.\n- Don't continue after a structured JSON error without branching on `error.code`.\n- Don't emit huge raw inventories to the user; save, summarize, and sample.\n\n<!-- File: CLAUDE.md (Tokens: ~1173 | Category: claude-rule) -->\n# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Quick commands\n\n```bash\npnpm install          # pnpm only — never npm/yarn\npnpm dev              # hot-reload Electron dev server (Vite + vue-tsc)\npnpm run build        # version bump → typecheck → vite bundle\npnpm run build:electron  # full build + electron-builder packaging\npnpm run test         # focused Vitest suite (Node env, aria2 + motrix + utils)\npnpm run test:clouddrive-cli  # clouddrive-cli tests only\npnpm run build:mac    # unsigned macOS .dmg/.zip\npnpm run build:mac:signed  # signed + notarized macOS\npnpm run build:linux  # Linux .deb/.AppImage/.pacman\npnpm run build:windows  # Windows .exe/.zip\npnpm run build:all    # cross-platform sequentially\npnpm run config:clean     # blank API keys in src/config.ts (pre-commit hook)\npnpm run config:restore   # restore real keys after commit\n```\n\n## Architecture (Electron + Vue 3 + Vite)\n\n```\nelectron/main/       Electron main process (entry: electron/main/index.ts)\n  core/              Window lifecycle, IPC, auto-update, protocol, dialogs\n  aria/              Aria2c download engine (config, UPnP, runtime)\nelectron/preload/    Preload scripts (IPC bridge)\n\nsrc/                 Vue 3 renderer\n  aliapi/            Alibaba Cloud Drive SDK (files, share, user, etc.)\n  cloudbaidu/        Baidu Netdisk provider\n  cloud123/          123Pan provider\n  cloud115/          115Pan provider\n  pikpak/            PikPak provider\n  onedrive/          OneDrive provider\n  dropbox/           Dropbox provider\n  box/               Box provider\n  quark/             Quark provider\n  cloud139/          CMCloud provider\n  cloud189/          Tianyi Cloud provider\n  pan/               File manager UI (tree, menus, dialogs)\n  media-server/      Jellyfin/Emby/Plex integration\n  down/              Download manager + Aria2 integration\n  layout/            Main layout views (PageVideo, PageMusic, etc.)\n  module/            Feature modules (audioplayer, musicsdk, lyricplayer, theme)\n  store/             Pinia stores\n  components/        Shared Vue components\n  utils/             Shared utilities\n  user/              Auth, account management UI\n\nshared/              Code shared between main + renderer (constants, config keys, UA)\nscripts/             Build scripts, CLI entry points (clouddrive-cli.mjs, clouddrive-mcp.mjs)\nclouddrive-cli/      Standalone CLI + MCP server package (npm: clouddrive-cli)\n  core/              Command implementations, MCP server, upload planning\n  providers/         8 cloud-drive provider implementations\n  media/             Media matching + rename logic\n```\n\nPath aliases: `@shared/*` → `shared/*`, `@main/*` → `electron/main/*`\n\n## Key patterns\n\n- **pnpm only** — lockfile is `pnpm-lock.yaml`; `package-lock.json`/`yarn.lock` are gitignored\n- **Node ≥ 18**\n- **Pre-commit hooks** (`nano-staged.mjs`): prettier + eslint on JS/TS, stylelint + prettier on Vue/CSS, typecheck on changed `src/` files\n- **Formatting**: single quotes, no semicolons, 260 printWidth, no trailing commas, LF, `sortAttributes: true` in Vue\n- **TypeScript**: strict mode, ESNext target, node moduleResolution\n- **Sensitive config**: `scripts/clean-config.js` blanks API keys pre-commit; restore with `pnpm run config:restore`\n- **Vitest**: Node environment only, explicit test directory list in `vitest.config.ts` (not glob patterns). Add new test dirs to config.\n- **CI**: Manual trigger only via `.github/workflows/release.yml`, publishes draft GitHub Release\n\n## clouddrive-cli (AI agent integration)\n\nStandalone CLI + MCP server for agent-driven cloud-drive operations. Supports 8 providers: aliyun, cloud123, 115, baidu, pikpak, onedrive, box, dropbox.\n\nKey bins: `clouddrive-cli` (CLI), `clouddrive-mcp` (MCP server). Both point to `scripts/clouddrive-cli.mjs` and `scripts/clouddrive-mcp.mjs` respectively.\n\nAgent rules when using the CLI:\n1. Discover commands first: `clouddrive-cli list --format json`\n2. Check capabilities: `clouddrive-cli providers capabilities --format json`\n3. Always dry-run before destructive ops\n4. Never invent file IDs — they must come from `files list`/`walk`/`search`/`tree`\n5. Use `--output <file.json>` for large results\n\n## Adding a new cloud-drive provider\n\nFollow the 15-step checklist in `AGENT.md` (OAuth → provider detection → file listing → download/playback → search → thumbnails → file operations → sharing → upload → media scan → folder picker → menu boundaries → properties/recycle bin → tests → verification). The checklist is authoritative — do not ship a provider that only does file listing.\n</yakaai_skills>"}