@extenshi/cli

中文文档
0.54.0发布于 2026/11/13ES Module近 30 天下载 6488

Pre-publish security scanner for browser extensions

原始使用文档
文档目录3 节
  1. Build map
  2. Localizing an extension
  3. Standalone Pay

@extenshi/cli

See the CLI documentation for scanning, project setup and publishing.

Build map

extenshi map opens a local page that shows the build of your extension as a map of steps: what is done, what an agent is working on, what waits on you, and what this extension does not need. It runs on 127.0.0.1 only, needs no network, and reads the project as it is on disk (manifest, icons, _locales, store assets, builds, CI workflows) plus the Dojo binding in .extenshi/project.json.

extenshi map             # start the map for this project and open it
extenshi map status      # progress, steps waiting on you, steps that can start; --json for everything
extenshi map stop        # stop the map server
extenshi map decline     # record that you do not want the map, so agents stop offering it
extenshi map step        # an agent reports a step: start, progress, done (with --file proof), stop
extenshi map review      # an agent offers you variants to choose from (icons, screenshots, listing copy)
extenshi map wait        # the agent waits until you pick one or ask for another round
extenshi map choose      # the agent records your answer from the chat

There is one map per project. Running extenshi map again, from another terminal or by another agent, finds the server that already runs and prints its address instead of starting a second one; an open tab is not duplicated. In a git worktree the map belongs to the main checkout, so agents working in parallel worktrees all report to the same page. The state lives in .extenshi/build-map.json of the main checkout; the server stops by itself after an hour with no page open and keeps its port for the next start.

Steps only you can do outside extenshi, such as a store developer account or a feedback form created in Dojo, have a Mark as done button in the step panel, with an optional note. The mark is written to .extenshi/build-map.json, so every agent and worktree sees it; undo next to the task takes it back.

No step on the way to a store needs a paid plan. Where the tool behind a step is ours, the step panel offers to do it yourself (the https link of your own privacy policy, uninstall survey or feedback form, your own permission reasons, the stores you upload to) or to skip it, with what skipping costs. Links you give are for a coding agent to write into src/extenshi.config.js. A skipped step a store asks for goes on a list of what to do in the store dashboards. Without release readiness from Dojo, Listing readiness is checked locally, and the store steps show the package on disk, the values to paste and the dashboard link before you press I submitted it for review.

Steps that spend Extenshi credits (security scan, compliance self-check, fixing findings, niche research, icon concepts, listing copy) show how many credits of their kind are left. Every account gets free ones once; without an account the step offers Sign in for free credits, the same browser pairing as extenshi login, with the code to check shown on the map. Marking such a step done yourself opens once its free credits are spent; skipping is always open. In a project with a map, extenshi scan leaves .extenshi/scan.json, and the map counts that scan while the package it names is unchanged on disk.

For the icon concept, the screenshots and the listing copy, an agent offers you variants on the map with extenshi map review. Open each preview from the step, then pick one or write what to change for another round; the agent gets your answer with extenshi map wait. Previews are served from your project files in a sandbox, so they cannot reach the map. Picking another variant later sends the steps built from the old pick back to run again.

Each done step says what it rests on: your mark, a project file (path and sha256) or a Dojo record. The map server keeps an evidence journal per step in the same file: when a fact appeared or went away, and every mark and undo. A step done only on your word has a hollow check; extenshi map status lists those steps, and map status --json adds each step's basis and the journal.

Localizing an extension

For an unpacked extension with literal English text, localize init ./extension --output ./extension-localized creates a new copy with localized manifest fields and static HTML text/display attributes (CLI 0.27.0+). The output must be new and outside the input, with an existing parent directory. A packaged external extenshi-i18n.js applies messages without replacing markup. JavaScript, form submission values and unsupported templates/CSP/encoding/sandbox pages remain unchanged and are reported in LOCALIZATION-REPORT.md. ZIP and JS/AST extraction are not included.

The free localize workflow operates on an unpacked, internationalized extension directory. It requires manifest.json with default_locale and _locales/<default_locale>/messages.json. It prepares requests for your own translator or coding agent; it does not call a translation service. The normal CLI telemetry preference still applies.

extenshi localize prepare ./extension --lang fr,de,es --output ./translation-request
# Translate messages in translation-request/localization-request.json.
# Review every requested message and add "reviewed": true to each locale object.
extenshi localize apply ./extension --translations ./translation-request/localization-request.json
extenshi localize check ./extension

Optional localization.json in the extension root:

{
  "version": 1,
  "sourceLocale": "en",
  "targetLocales": ["fr", "de", "es"],
  "protectedTerms": ["Acme"]
}

With this configuration, --lang is optional. All three commands accept --protect Acme,Product to add exact terms that must remain when they occur in the original message. Prepared requests include the configured terms. Configure durable terms in localization.json, or repeat --protect when applying/checking.

A reviewed request has this shape (the actual source hashes come from prepare):

{
  "version": 1,
  "sourceLocale": "en",
  "locales": {
    "fr": {
      "reviewed": true,
      "sourceHashes": { "greeting": "sha256-from-prepare" },
      "messages": { "greeting": { "message": "Bonjour" } }
    }
  }
}

Only missing, untracked, source-changed or target-edited keys appear in the request. A locale may also include removeKeys for keys deleted from the source; review these removals before setting reviewed: true. Apply removes them from the target catalog and tracking state, and refuses removal if the key has returned in the source. Existing translations remain intact when other keys are applied. .extenshi-localization.json records source and reviewed target hashes only after successful apply; keep it in source control. Direct target edits require another review. Older source-only state also requires re-review before check passes. An unchanged second prepare contains no locale requests. Use a fresh output directory each time: prepare refuses to overwrite translator work.

Apply requires a reviewed bundle and rejects unknown keys, empty messages, changed placeholders, changed positional substitutions or dollar escapes, missing protected terms, stale source hashes, invalid locale paths and symlinked workspace files. It validates all requested locales before writing and checks localized manifest lengths plus new findings from the existing listing risk rules against the default locale. Manifest checks resolve case-insensitive message names, static named placeholders and dollar escapes before measuring visible text. Manifest strings that require runtime positional arguments are rejected; use static content there. Checks are heuristic and cannot certify translation accuracy or store acceptance. Complete translations are required for each applied locale; sparse browser fallback catalogs need their missing keys translated first.

check prints JSON and exits with status 1 for missing, stale, unreviewed or invalid translations, including target locales configured but not created. A project that keeps its own translations (for example a script that writes every messages.json) has no .extenshi-localization.json, so nothing there was ever reviewed through prepare/apply. Without that file check runs in parity-only mode, or run check ./extension --parity-only yourself: it compares every locale with the default locale for missing or extra keys, changed $NAME$, $1 and $$ tokens and placeholders definitions, empty or malformed messages, reserved @@ names, case-only duplicates, a missing default_locale directory and locale directories Chrome ignores, plus the same listing-risk and manifest length findings review mode reports; it ignores review state. See the localization guide for the rule list. The JSON reports "mode" and, when the mode was chosen automatically, a note. This workflow covers extension message catalogs, including localized manifest text. Full store descriptions and screenshots need separate localization. RTL text is accepted for supported locales, but visual direction, overflow and interaction need testing in the target browser.

Standalone Pay

extenshi pay works without a local repository, project binding, or Extenshi development project. It requires a backend with standalone Pay support and explicit Pay permissions on your API key, granted at API keys. Existing keys have no Pay access by default.

extenshi pay list
extenshi pay create --input '{"name":"My extension"}' --apply
extenshi pay readiness --input '{"appId":"<application-uuid>"}'
extenshi pay connect --input '{"appId":"<application-uuid>"}' --apply
extenshi pay seller --input '{"appId":"<application-uuid>"}'
extenshi pay profile --input-file seller-profile.json --apply
extenshi pay offer-upsert --input-file offer.json --apply
extenshi pay enable --input '{"appId":"<application-uuid>","enabled":true}' --apply
extenshi pay export --input '{"appId":"<application-uuid>","resource":"payments"}' --output payments.jsonl

Every mutation requires --apply; this is an explicit operation, not a dry-run endpoint. connect returns a URL for the author to complete Stripe KYC. Agreements must be accepted in the browser. Readiness and actual SDK registry availability must be checked before launch. The CLI never accepts agreements or creates platform-owned sellers.

Use link with { "appId": "...", "projectId": "..." } to attach an optional development project, and unlink to remove the link. archive preserves existing payment data. offer-archive takes appId and sku. trial takes appId and trialDays (0–365, or null to turn the free trial off). rotate-key generates a new publishable SDK key; prior public keys remain accepted for installed builds. This is not secret revocation. Do not blindly retry create, connect, or rotation after a timeout.

Profile JSON: { "appId": "...", "profile": { "displayName": "Author-confirmed name", "supportUrl": "https://example.com/support", "termsUrl": "https://example.com/terms" } }. Offer JSON: { "appId": "...", "sku": "pro", "kind": "subscription", "interval": "month", "amountMinor": 499, "currency": "usd", "title": "Pro", "features": ["premium"] }. A one-time or lifetime offer uses interval: null.

extenshi pay payment-evidence --input '{"appId":"..."}' prints what Extenshi's payment ledger proves about the application, per mode: checkout completed, license issued, an installation received the signed license, restored on a second installation, refund revoked. It is derived from provider-signed webhooks, carries opaque IDs and timestamps only, and is the same evidence extenshi release status uses for the payment check of a linked project. Only a live-mode purchase satisfies a release's payment requirement.

extenshi pay test-cycle --app <appId> [--sku pro] [--refund-key-env NAME] runs one Stripe TEST-mode purchase against an application whose seller is in test mode and prints that evidence. It refuses a live seller, a non-test Checkout session and a non-test refund key. The CLI acts as the installation: it opens a checkout, prints the hosted URL for payment with card 4242 4242 4242 4242, waits for the webhook, verifies the signed license, optionally refunds with the Stripe TEST secret named by --refund-key-env and checks the signed revocation. Test-mode purchases are recorded and shown but do not satisfy a release's payment requirement.

Without --output, export returns one page with nextCursor; pass that cursor to retrieve the next page. With --output, all pages are streamed to a new private (0600) JSONL file; existing files are never overwritten, and failures remove incomplete files. Resources: offers, payments, subscriptions, entitlements, customers. Keep exports private. Only the publishable SDK key belongs in extension code.

版本与发布记录

@extenshi/cli 共发布 80 个版本,首次发布于 2026/06/05;过去 12 个月发布了 80 个版本。

版本发布日期距今
0.54.0latest2026/11/131 天前
0.53.52026/11/122 天前
0.53.62026/11/122 天前
0.53.42026/11/112 天前
0.53.32026/11/112 天前
0.52.02026/11/112 天前

关于 @extenshi/cli 的常见问题

@extenshi/cli 是什么?

Pre-publish security scanner for browser extensions

如何安装 @extenshi/cli?

在项目目录运行 npm install @extenshi/cli,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 extenshi,可以用 npx extenshi 直接运行。

@extenshi/cli 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/extenshi__cli 是否存在。

@extenshi/cli 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@extenshi/cli 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@extenshi/cli 可以商用吗?

@extenshi/cli 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@extenshi/cli 的下载量有多少?

根据 npm 官方下载统计,@extenshi/cli 在 2026/10/14 – 2026/11/12 这 30 天内被下载 6,488 次,日均约 216 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@extenshi/cli 还在维护吗?

最新版本 0.54.0 发布于 2026/11/13(1 天前);至今共发布 80 个版本,其中过去 12 个月发布了 80 个;首次发布于 2026/06/05。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。