Files

19 KiB

Web Tools Agent Guide

This file is mandatory for AI and coding agents working in this repository. Read README.zh-CN.md in full before changing code. It is the authoritative product, behavior, deployment, extension, and release document; README.md is a complete English overview.

First actions in a new session

  1. Run git status --short --branch and preserve all existing tracked and untracked work. Never revert, overwrite, or clean user changes without explicit permission.
  2. Read the closest existing tool component, its src/lib/ implementation, Worker if present, and related tests before editing behavior.
  3. Inspect shared/tool-catalog.json, shared/default-navigation.json, and src/tools/registry.ts before adding or removing a tool.
  4. Do not commit, create tags, or push unless the user explicitly requests that action in the current conversation. Never place access tokens or credentials in source, Git configuration, documentation, commands committed to the repository, or release artifacts.
  5. Make source changes only. Do not edit generated dist/; rebuild it with npm run build.

Product identity and non-goals

  • Web Tools is an anonymous-access, self-hosted Vue 3 + TypeScript browser-local tools application with a zero-dependency Node.js static/configuration server.
  • The default production port is 9000. Port 8081 is only the local Vite development proxy target.
  • The application is anonymous. Do not add login, accounts, favorites, sponsorship, analytics, telemetry, advertising, CDN assets, or a database.
  • A deployment may place Cloudflare in front of the origin. The server's per-response CSP nonce exists only to support Cloudflare JavaScript Detections without unsafe-inline; it is not permission to add application analytics, telemetry, or remote tool processing.
  • Tool inputs, keys, files, images, and results must remain inside the current browser tab. Do not send them to the Node server, a third-party API, or any remote service.
  • /tools/setting is the fixed, unlisted route for navigation management. It has no authentication and is not a security boundary. Anyone who can access the application can open it and change the globally shared navigation order.
  • The first-run default category order is encoding, checksum, crypto, formatting, image; an existing saved navigation file keeps its custom order and is never reset by a release.
  • The server persists only navigation configuration. Preserve data/navigation.json and the configured external data directory; writes must remain temporary-file plus atomic-replace operations.
  • Multiple users and tabs may use every tool concurrently. Their calculation state must remain independent; only navigation order is globally shared.

Architecture rules

  • package.json is the sole authoritative application version.
  • shared/tool-catalog.json is the authoritative category/tool catalog. shared/default-navigation.json defines first-run ordering.
  • Each tool is an independent lazy-loaded Vue component under src/tools/; register it in src/tools/registry.ts.
  • Routes and sidebar entries are generated from the registry and catalog. Do not manually add an ordinary tool route to src/router.ts.
  • Put parsing, encoding, cryptography, validation, and file-generation logic in testable modules under src/lib/. Vue components own presentation and state, not algorithm implementations.
  • Put expensive file parsing and calculation in src/workers/. Workers still run entirely in the browser.
  • CRC, Firmware Hash, and RSA Signature Verification file mode use src/components/FileDropField.vue for initial selection, loaded-file summaries, drag replacement, explicit replacement, clear actions, and busy feedback. PNG/ICO has a separate image preview/conversion workspace and must not be forced into this component unless its interaction model is deliberately redesigned.
  • File tools whose Worker protocol parses a file and then reuses that Worker for calculation should use src/composables/useTransactionalFileWorker.ts. Keep each tool's algorithms, Worker message types, and Vue state independent.
  • Prefer browser standard APIs or existing, reviewed dependencies. Do not hand-roll established cryptographic primitives or file parsers.
  • Add dependencies only when necessary. Keep the Node server runtime dependency-free unless a requirement cannot reasonably be met with the standard library.
  • Define and enforce resource limits for file sizes, record counts, blocks, decoded image dimensions, random output, and rendered syntax tokens. If a limit changes, update implementation constants, tests, and the limits table in README.zh-CN.md together.

Stable tool behavior

  • UTF-8 / Hex has the permanent tool ID utf8-hex and route /tools/utf8-hex. It uses strict UTF-8 conversion. Hex input accepts continuous text or chunks separated by whitespace, English commas, or Chinese commas, with an optional 0x prefix on each chunk. Invalid UTF-8 must fail rather than silently replace bytes.
  • Base64 supports standard and URL-safe input. Decoded output supports strict UTF-8, continuous Hex, and 0xNN, ... byte arrays. Reject invalid characters, padding placement, lengths, and non-canonical trailing bits.
  • AES-CMAC accepts exactly 16, 24, or 32 key bytes for AES-128, AES-192, or AES-256, defaulting to 16 bytes. Never pad or truncate the key. Key and Hex-message input accepts continuous Hex or whitespace/comma/Chinese-comma-separated chunks with optional 0x prefixes. The CMAC tag remains exactly 16 bytes for every key size. Preserve RFC 4493 AES-128 and NIST SP 800-38B AES-192/256 vectors.
  • CRC supports inline Hex bytes, BIN, and multi-block Intel HEX, with 16 reviewed CRC-8/16/32/64 presets and custom Width, Poly, Init, XorOut, RefIn, and RefOut. Keep canonical preset names and visible aliases synchronized with src/lib/crc.ts: CRC-8/SMBUS, MAXIM-DOW, SAE-J1850; CRC-16/ARC, DNP, IBM-3740, IBM-SDLC, KERMIT, MODBUS, USB, XMODEM; CRC-32/ISO-HDLC, ISCSI, MPEG-2; CRC-64/ECMA-182, XZ. Show the ambiguous CCITT alias only alongside KERMIT and CCITT-FALSE only alongside IBM-3740; never collapse them into one ambiguous preset. Inline Hex uses the shared strict byte parser: accept continuous Hex or chunks separated by whitespace, English commas, or Chinese commas, with an optional 0x prefix on each chunk; reject empty input. Limit it to 1 MiB after parsing and 6 MiB of source characters, and parse/calculate it in a dedicated Worker. The Chinese UI labels RefIn/RefOut as input/output bit reversal; these flags do not reverse byte order or the complete input. Combined file data is ordered by address without filling gaps, and per-block results remain available.
  • Firmware Hash accepts Intel HEX and computes SHA-256 and SHA-512. Effective-data mode concatenates sorted blocks without gap filling. Block-header mode prepends exactly two binary uint32 values, startAddress and data-only dataLength, to every block. Both fields are four bytes; Big Endian is the default; total input is Header1 || Data1 || Header2 || Data2 .... Never hash a textual Hex representation of the header.
  • RSA allows 2048, 3072, and 4096-bit keys with public exponent 65537. Prefer Web Crypto; dynamically load the node-forge fallback only when needed, and seed it from crypto.getRandomValues. Export public SPKI PEM, private PKCS#8 PEM, and separately copyable N/E continuous Hex or byte arrays.
  • RSA Signature Verification is verification-only. Default to RSA-PSS; support switching between PKCS#1 v1.5 and RSA-PSS with SHA-256/384/512, and do not add SHA-1. Accept one SPKI, PKCS#1 public-key, or X.509 certificate PEM block, or N/E Hex parameters. Treat E as an unsigned Hex integer: accept odd-length input by padding one zero nibble on the left, so 10001 and 010001 both mean decimal 65537; other Hex byte inputs remain even-length. X.509 support only extracts the RSA public key and displays metadata; never represent it as certificate-chain, issuer, usage, validity, or trust validation. Verification accepts 1024-8192-bit moduli and warns below 2048 bits; key generation remains restricted to 2048/3072/4096 bits.
  • Signature data modes are exact: UTF-8 uses the original text bytes, Hex uses parsed bytes, raw-file mode uses every file byte, and Intel HEX effective-data mode concatenates sorted blocks without gap filling or block headers. Intel HEX block-header mode uses the same binary contract as Firmware Hash: prepend uint32 startAddress and uint32 data-only dataLength to every block, default to Big Endian, allow explicit Little Endian, and verify Header1 || Data1 || Header2 || Data2 .... Never infer or silently switch file semantics from the filename. PSS salt length is explicit; its default is the smaller of the selected hash length and the current modulus encoding bound, and it must not exceed that bound. Distinguish an invalid signature from malformed input or execution failure.
  • Secure random output comes only from crypto.getRandomValues, defaults to 16 bytes, is limited to 1-65,536 bytes, and supports continuous Hex, spaced Hex, and byte arrays. Changing display format must not regenerate bytes. Missing or failed cryptographic sources must fail closed without a pseudorandom fallback.
  • JSON/XML formatting, minification, validation, and syntax highlighting stay local. XML parser failures are identified by the browser parser-error namespace; a valid user element named parsererror must not be rejected. When highlighting limits are exceeded, render the complete result as plain text rather than truncating it.
  • PNG/ICO processing stays local and must enforce both compressed-file and decoded-pixel limits before costly rendering or allocation.

Intel HEX and asynchronous safety

  • Treat every address, length, end-address, offset, and allocation calculation as checked uint32 arithmetic. JavaScript bitwise operators are signed 32-bit and must not be used as unchecked address arithmetic.
  • Validate record syntax, byte counts, checksums, control-record lengths/addresses, EOF placement, extended addresses, and the 0xFFFFFFFF boundary.
  • Sort records by absolute address, merge contiguous records, deduplicate identical overlaps, and reject conflicting overlaps. Enforce record, block, and effective-byte limits before allocating combined buffers.
  • The default Intel HEX effective-data allocation limit is 64 MiB (DEFAULT_MAX_INTEL_HEX_BYTES); keep it aligned with MAX_FIRMWARE_FILE_SIZE and the limits table in README.zh-CN.md.
  • Navigation GET normalization and PUT writes are serialized within each Node process. Do not remove that lock without replacing it with an equally strong concurrency design.
  • CRC and Firmware Hash may share the reviewed Intel HEX parser but must keep separate calculation logic, Worker protocols, and Vue state.
  • File replacement, clear, mode change, option change, repeated generation, and component unmount can invalidate asynchronous work. Terminate obsolete Workers where possible and use monotonically increasing request/version IDs. A stale Worker, file read, image decode, or key-generation result must never replace current state.
  • Treat file replacement as a transaction: parse a candidate in a separate pending Worker and commit it only after successful parsing. Invalid candidates and pending-Worker failures must preserve the active Worker, current file summary, and existing results; only a successful commit clears results and terminates the previous active Worker.
  • Clear the native file input value after handling a selection so choosing the same file again still emits a change event.
  • Worker messages must be correlated to both the active Worker instance and active request ID. Error and completion handlers must ignore stale instances.

UI contract

  • Preserve the application shell: navigation on the left and tool content on the right on desktop; responsive navigation and a vertical content flow on mobile portrait.
  • All tools use the shared visual language. Prefer ToolPage, TextEditor, ModeTabs, existing form/action classes, Lucide icons, and src/styles.css; do not create a tool-specific theme.
  • Keep desktop controls compact. Use stable grid/flex constraints and allow controls to become full-width where appropriate on narrow screens.
  • Prevent horizontal page overflow, clipped controls, nested scrolling accidents, text overlap, layout shifts, and unbounded result columns. Long Hex, hashes, filenames, and table cells require explicit wrapping or contained scrolling.
  • Version information remains at the bottom of the sidebar and is read from package.json. Every page footer displays exactly Copyright © mid All Rights Reserved.
  • Do not add a visible link to /tools/setting, explanatory marketing copy, login UI, favorites, or sponsorship UI.
  • Every native input, select, and textarea must have a unique id and stable name. TextEditor requires an explicit id and uses it as the default name; preserve the existing implicit or explicit label association.
  • Preserve the application icon contract under public/: favicon.svg, a 16/32/48-frame favicon.ico, apple-touch-icon.png at 180x180, icon-192.png, icon-512.png, icon-maskable-512.png, and site.webmanifest. Keep the icon visually aligned with the sidebar brand and keep the maskable artwork inside its safe zone.
  • The manifest is metadata/install-ready only. Do not add a Service Worker, offline cache, install prompt, splash-screen bundle, Safari mask icon, legacy browserconfig.xml, redundant Apple sizes, or separate 16/32 PNG favicons unless requirements explicitly change.
  • Preserve the share metadata contract: the single user-facing description is exactly 一个匿名访问、自托管的浏览器本地工具箱, represented by the standard HTML description and the identical og:description compatibility field. Do not add a custom share image, other Open Graph or platform-specific metadata, platform crawlers, route-specific previews, tool lists, or user data. Sharing clients may fall back to the document title and existing favicon assets, but their final preview and cache behavior remain platform-controlled.
  • For UI work, verify a wide desktop, an intermediate width around 801-1040 px, and mobile portrait around 390 x 844 in a real browser. Check direct routes, refresh, navigation, search, /tools/setting, both themes, console errors, and network requests.

Adding a tool

  1. Choose a permanent, unique kebab-case ID. IDs must remain stable after publication because routes and saved navigation depend on them. The recorded pre-0.2.0 correction from ascii-hex to utf8-hex is the sole existing ID migration. setting is reserved by /tools/setting and cannot be used as a tool ID.
  2. Add pure logic and normal, invalid, boundary, resource-limit, and known-vector tests.
  3. Add one Vue component under src/tools/ using shared components and responsive styles.
  4. Add matching metadata to shared/tool-catalog.json and its default position to shared/default-navigation.json. Only change navigation version: 1 for a schema migration, not for a new tool.
  5. Register the Lucide icon and lazy component in src/tools/registry.ts. Do not add a manual route.
  6. Verify that an old saved navigation.json retains its order and receives the missing tool after the Node process restarts and navigation is next loaded.

IDs must remain synchronized across the catalog, default navigation, icon map, and component registry. Existing catalog tests enforce this contract. The ascii-hex ID is a legacy input accepted only while normalizing existing navigation.json files; it migrates in place to utf8-hex. Do not restore it as a catalog ID, component key, form-field prefix, or route.

Deployment and release

  • Supported deployments are Docker and Node.js 22.12.0+ with web-tools.ps1 on Windows Server. A Windows single EXE is an optional future deliverable and is not currently built or supported.
  • Keep production port changes synchronized across server/index.mjs, web-tools.ps1, Dockerfile, docker-compose.yml, .env.example, deployment tests, and both READMEs where applicable.
  • The Windows update flow requires a clean main checkout and uses git pull --ff-only. Preserve external C:\ProgramData\WebTools\data state.
  • Running web-tools.ps1 without an action is an interactive user entry point and must keep the start/update/update-without-start/exit menu. Scheduled tasks and automation must pass an explicit start or update action so they never wait for input.
  • New catalog data is loaded by the Node process at startup. Rebuilding dist alone is insufficient after catalog changes; restart the server and refresh already-open browser pages.
  • Preserve the per-response 128-bit CSP nonce generated with node:crypto. Cloudflare parses the nonce from the response header for JavaScript Detections. Never replace it with a fixed nonce or unsafe-inline; keep HTML uncached/no-cache so a document and its nonce cannot become mismatched.
  • Keep one-year immutable caching limited to fingerprinted files under dist/assets/. Stable filenames such as HTML, favicon assets, and site.webmanifest must use no-cache so a deployment can replace them safely.
  • Browser navigation PUT requests carrying Fetch Metadata must be same-origin. Requests without Sec-Fetch-Site remain supported for non-browser administration, so document this as defense in depth and never as authentication.
  • If a single EXE is later authorized, use Node.js SEA with embedded read-only web/catalog assets and an external writable data directory. Add per-architecture builds, asset-read abstraction, Windows smoke tests, replacement/update instructions, and optional Authenticode signing. Derive EXE version metadata from package.json; do not create another manually maintained version source. Do not commit generated executables.

For a release, synchronize these five tracked files:

  1. package.json
  2. package-lock.json
  3. docker-compose.yml
  4. README.zh-CN.md
  5. CHANGELOG.md

Use an npm/SemVer-compatible calendar version in YYYY.M.D form, without leading zeroes in the numeric fields; for example, 2026.8.22. Allow at most one final release per calendar day and use YYYY.M.D-rc.N only for prerelease validation. Run npm version YYYY.M.D --no-git-tag-version so the project version in package.json and the two project metadata entries in package-lock.json remain synchronized. Other lockfile version fields belong to dependencies. README.md intentionally does not hardcode the current version.

Rebuild dist, the requested delivery ZIP, optional Docker image tar, and SHA-256 checksums. Generated assets are release outputs and remain ignored by Git. Never include node_modules, .env, runtime data, credentials, or local logs.

Required validation and handoff

  • After every code or documentation change, run npm run check and git diff --check.
  • Before a release, also run npm audit --audit-level=low.
  • For server/deployment changes, validate PowerShell syntax and Docker Compose configuration when the required executables are available. State clearly when a platform-specific check could not be run.
  • For UI changes, complete the browser matrix in the UI contract. Automated tests and a successful build do not replace visual verification.
  • Report changed behavior, important format/compatibility decisions, tests actually run, and any remaining risk. Report artifact paths and SHA-256 only when the task requested artifacts.
  • Do not claim a check passed unless it was actually executed in the current worktree.