@chughtapan/safer-architecture-lsp

中文文档
0.3.1发布于 2026/08/15Apache-2.0TypeScriptES Module构建来源已验证近 30 天下载 3244

Whole-project TypeScript architecture analyzer: a check CLI for CI and agents, a stdio LSP for editors, and reason-carrying suppression waivers.

原始使用文档
文档目录10 节
  1. CI in two minutes
  2. Editor / agent setup
  3. Configuration
  4. CUPID domain enforcement
  5. Rules
  6. Suppressions (waivers)
  7. Programmatic API
  8. Scope and limits (read before adopting)
  9. Troubleshooting
  10. Development

safer-architecture-lsp

Whole-project TypeScript architecture analysis with a deterministic CI gate and live editor diagnostics. It builds a real ts.Program, derives the folder-level import graph, and reports structural findings — cycles, layering violations, oversized public surfaces, boundary leaks — with every suppression carrying a written, auditable reason.

Why this instead of an ESLint rule? Whole-project analysis doesn't fit a per-file lint model, and per-keystroke re-analysis doesn't fit CI tools. This package runs one warm analysis core behind two surfaces: a check command whose exit code CI can trust, and a Language Server that streams the same findings into the diagnostics channel your editor — or your coding agent — already reads. An agent that introduces a cycle sees the diagnostic while authoring, and the escape hatch is one line it must justify: that inline feedback loop, with a queryable waiver ledger, is the wedge.

Status: 0.x. Rule heuristics are young; expect to configure. See the 0.x stability policy in CHANGELOG.md.

CI in two minutes

npm install --save-dev @chughtapan/safer-architecture-lsp
npx safer-architecture-lsp check .

check analyzes the project once and exits 0 (clean), 1 (findings), or 2 (could not analyze — bad root, invalid config, unusable tsconfig). It always prints a summary line, so an empty result is distinguishable from a run that never happened:

safer-architecture check: 0 finding(s) across 0 file(s), 4 waiver(s), 1 project(s), options from file — /repo

--json emits the merged report (projects, diagnostics, waivers, and deterministic analysis snapshots) for machine consumption; --waivers prints the suppression ledger with reasons.

check writes a persistent report to node_modules/.cache/safer-architecture-lsp/, keyed by a content watermark over the project's sources, package.json, and tsconfig. A repeat run on an unchanged project reuses it instead of rebuilding the ts.Program, so cache that directory in CI to amortize cold cost.

For a monorepo, add an explicit safer-architecture.workspace.json at the root. Paths are literal and relative—there is no implicit discovery or glob expansion:

{ "packages": ["packages/api", "packages/web"] }

Every listed directory must exist and have a unique, non-empty package.json name. The CLI and LSP analyze each package with its own config/cache, merge the reports, and reject runtime/peer dependency cycles. An invalid manifest blocks the workspace loudly.

Editor / agent setup

The serve subcommand speaks LSP over stdio:

// Claude Code plugin.json
{
  "lspServers": {
    "safer-architecture": {
      "command": "safer-architecture-lsp",
      "args": ["serve"],
      "extensionToLanguage": { ".ts": "typescript", ".tsx": "typescriptreact" }
    }
  }
}

Any stdio LSP client works the same way (command: safer-architecture-lsp, args: ["serve"]). Diagnostics are published for every analyzed file, not just open ones, and each finding deep-links its rule reference. Hosts that cannot run two servers for one file extension can front this server with the bundled safer-lsp-proxy multiplexer alongside typescript-language-server: the first backend in its config is primary, and a sidecar crash never takes the primary down. See the LSP server guide for workspace discovery, diagnostic lifecycle, and teardown behavior.

Verify it's alive: stderr logs one line per workspace registration and per publish (published N finding(s) across M file(s) … in Xms).

Configuration

Put safer-architecture.config.json at the project root (each listed package has its own file in an explicit workspace). It is schema-validated; an invalid file makes check exit without analysis and surfaces as an error diagnostic in the editor, where defaults keep diagnostics available while you repair it. Edits hot-reload the affected project. The knobs you'll actually touch first:

{
  // Third-party types intentionally part of your public API:
  "publicTypePackages": [
    { "package": "typescript", "reason": "our contract is ts.Program-shaped" }
  ],
  // Folders siblings may import freely (your shared kernel):
  "sharedFolderNames": [
    { "folder": "analyzer", "reason": "one analysis core, many surfaces" }
  ],
  // Deliberate non-index facade files:
  "facadeFiles": [
    { "file": "server/workspace-engine.ts", "reason": "engine contract" }
  ],
  // Public-surface budgets (defaults shown):
  "maxPublicExports": 20,
  "maxSubpathExports": 5
}

Every allowance entry requires a reason — writing it is the architectural decision. The full option list lives in docs/rules.md, mapped rule-by-rule to the options that control it. This repository's own safer-architecture.config.json is a working example: CI runs check . on this codebase and fails on any unwaived finding.

CUPID domain enforcement

Domain enforcement is opt-in and strict once domains is non-empty:

{
  "domains": [{
    "name": "orders",
    "roots": ["src/orders"],
    "entrypoints": ["src/orders/index.ts"],
    "reason": "owns the order lifecycle"
  }],
  "domainOwnership": [{
    "path": "src/legacy-orders",
    "domain": "orders",
    "reason": "migration ownership is explicit"
  }],
  "compositionRoots": [{
    "path": "src/bootstrap.ts",
    "reason": "application wiring edge"
  }]
}

Production modules must be owned by an inferred domain root, an explicit ownership override, or a reason-carrying composition root. Cross-domain imports must target destination entrypoints; domain dependencies must be acyclic; and side-effect-only cross-domain imports are restricted to composition roots. See CUPID enforcement.

Rules

The complete reference — what each rule flags, why, its controlling options, and how to fix it — is docs/rules.md. Categories: import topology (cycles, layering, sibling domains), public surface (curation, size budgets, vendor-type leaks), folder shape (size, READMEs, explicit APIs), and module shape (accidental boundaries, trivial indirection, fat orchestrators).

Suppressions (waivers)

One comment line, file-scoped, reason mandatory:

// safer-arch-ignore no-trivial-sink-file: deliberate seam; the overlay follow-up grows here.

A missing or empty reason is itself a diagnostic. Granted waivers are retained with their reasons and queryable via check --waivers — an auditable ledger, not a muted warning. Unknown rule ids error. The legacy two-line @agent-code-guard/architecture-exception marker from this code's previous life is never honored and always errors, so a stale suppression cannot silently stop working.

Programmatic API

import {
  analyzeResolvedArchitecture,
  resolveArchitectureOptions,
} from "@chughtapan/safer-architecture-lsp";

const options = resolveArchitectureOptions({ projectRoot: process.cwd() });
const report = analyzeResolvedArchitecture(options);
for (const d of report.diagnostics) console.log(d.ruleId, d.file, d.message);
for (const w of report.waivers) console.log("waived", w.ruleId, w.reason);

The exported report types include deterministic analysis snapshots, and the exported option types include domain definitions, ownership overrides, and composition roots for typed configuration builders.

Scope and limits (read before adopting)

  • Module edges use TypeScript's cached resolver, including paths and package imports aliases. Workspace package topology comes from declared runtime and peer dependencies; cross-package source/project-reference imports remain scoped to each package's TypeScript project.
  • Analysis is save-time in the editor; live keystroke-level diagnostics are a follow-up.
  • A tsconfig found above the workspace root is scoped to the workspace's files automatically.

Troubleshooting

  • No diagnostics at all? Check stderr. A missing/broken tsconfig now surfaces as an architecture-analysis-unavailable error diagnostic — if you see literally nothing, your client isn't connected (serve missing from args is the common cause; a bare invocation prints help and exits instead of hanging).
  • "config INVALID" in stderr / squiggle on the config file — the JSON failed schema validation; the message names the offending key.
  • Findings vanished after an edit? The engine hot-reloaded with your new config; run check --waivers to see what is being suppressed.

Development

npm install
npm run build   # tsc → dist/
npm test        # vitest: analyzer fixtures, CLI contract, proxy, full LSP session
npm run test:coverage # c8 ratchet + per-directory floors; runs pre-push, not in CI
npm run lint    # eslint (agent-code-guard policy) + knip
node dist/server/index.js check .   # the dogfood gate CI enforces

Coverage runs pre-push, not in CI: c8 slows the process-spawning suites enough
to push the slowest property test past vitest's timeout on CI hardware. `npm
install` wires the hook up through husky, so there is nothing to install by
hand. Bypass it with `SKIP_COVERAGE=1 git push`.

husky takes over `core.hooksPath`, so anything already in `.git/hooks/pre-push`
would stop running; `.husky/pre-push` chains it explicitly.

Publishing: push a vX.Y.Z tag matching package.json — the publish workflow builds, tests, lints, self-checks, then publishes to npm via trusted publishing.

版本与发布记录

@chughtapan/safer-architecture-lsp 共发布 3 个版本,首次发布于 2026/07/23;过去 12 个月发布了 3 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.3.1latest2026/08/152 个月前
0.2.02026/07/243 个月前
0.1.02026/07/233 个月前

关于 @chughtapan/safer-architecture-lsp 的常见问题

@chughtapan/safer-architecture-lsp 是什么?

Whole-project TypeScript architecture analyzer: a check CLI for CI and agents, a stdio LSP for editors, and reason-carrying suppression waivers.

如何安装 @chughtapan/safer-architecture-lsp?

在项目目录运行 npm install @chughtapan/safer-architecture-lsp,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 safer-architecture-lsp、safer-lsp-proxy,可以用 npx safer-architecture-lsp 直接运行。

@chughtapan/safer-architecture-lsp 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@chughtapan/safer-architecture-lsp 支持 ESM 还是 CommonJS?

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

@chughtapan/safer-architecture-lsp 需要什么版本的 Node.js?

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

@chughtapan/safer-architecture-lsp 可以商用吗?

@chughtapan/safer-architecture-lsp 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@chughtapan/safer-architecture-lsp 的下载量有多少?

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

@chughtapan/safer-architecture-lsp 还在维护吗?

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