- Use
pnpmfor all package management and repo scripts. - Install dependencies:
pnpm install - Lint:
pnpm run lint - Type-check:
pnpm run typecheck - Build:
pnpm run build - Full test suite:
pnpm run test - Watch tests:
pnpm run test:watch - Run one test file:
pnpm exec node --import tsx --test tests/serve.test.ts - Run one test by name:
pnpm exec node --import tsx --test --test-name-pattern "should return health status" tests/serve.test.ts - CLI/manual smoke flows already scripted in
package.json:pnpm run test:binpnpm run test:servepnpm run test:serverPublishpnpm run test:realPublish
- This repository is a thin TypeScript CLI/server layer over
@wenyan-md/core/wrapper. Rendering, theme management, credential storage, and WeChat publishing are mostly delegated to the core package; repo-local logic mainly handles command wiring, input resolution, and the HTTP server wrapper. src/cli.tsis the real entrypoint. It defines thepublish,render,theme,serve, andcredentialcommands with Commander, exportscreateProgram()for tests, and only callsprogram.parse()behindimport.meta.main.src/utils.tscentralizes content ingestion. Input precedence is inline argument > file/URL via--file> stdin. File input is normalized withgetNormalizeFilePath()and returnsabsoluteDirPathso core rendering can resolve relative assets correctly.src/commands/serve.tsimplements the remote publish server used bywenyan publish --serve .... The flow is:/uploadaccepts Markdown, CSS, JSON, and image files intoconfigDir/uploads- clients reference uploaded assets via
asset://... /publishloads an uploaded JSON render payload, rewritesasset://references back to temp files, and callspublishToWechatDraft()
- The project supports both direct local publish and client-server publish. Local mode calls WeChat APIs from the CLI process; server mode pushes render/publish work to a remote Express server to avoid local IP whitelist issues.
- Keep the codebase in ESM TypeScript (
"type": "module",moduleResolution: "NodeNext"). Preferimport/export, not CommonJS. - Preserve the current error-handling split:
- CLI commands should go through the shared
runCommandWrapper()pattern and exit with code 1 on failure. - Server routes should throw
AppErrorfor expected client errors so the shared JSON error shape stays{ code: -1, desc }.
- CLI commands should go through the shared
- Preserve user-facing Chinese success/error messages unless there is a strong reason to change them. Tests assert on specific Chinese output and error text.
- When adding input-related behavior, keep the existing precedence rules and do not break stdin-based usage for CI/CD pipelines.
- Server uploads are temporary and live under
configDir/uploadswith a 10-minute TTL cleanup job. Features that rely on uploaded files should fit that lifecycle instead of introducing permanent storage here. - Publishing assumes Wenyan article metadata conventions from the README: Markdown frontmatter should provide at least
title, with optionalcover,author, andsource_url. WeChat publishing also depends onWECHAT_APP_IDandWECHAT_APP_SECRETunless credentials are managed through the CLI/server credential flow. - Tests use the native Node test runner (
node:test) plusnode:assert/strictandmock. Follow the existing style instead of introducing Jest/Vitest.