@mcptoolshop/shipcheck 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ja.md ADDED
@@ -0,0 +1,105 @@
1
+ <p align="center">
2
+ <a href="README.md">English</a> | <a href="README.zh.md">中文</a> | <a href="README.es.md">Español</a> | <a href="README.fr.md">Français</a> | <a href="README.hi.md">हिन्दी</a> | <a href="README.it.md">Italiano</a> | <a href="README.pt-BR.md">Português (BR)</a>
3
+ </p>
4
+
5
+ <p align="center">
6
+ <img src="https://raw.githubusercontent.com/mcp-tool-shop-org/brand/main/logos/shipcheck/readme.png" alt="Shipcheck" width="400">
7
+ </p>
8
+
9
+ <p align="center">
10
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT License"></a>
11
+ <a href="https://mcp-tool-shop-org.github.io/shipcheck/"><img src="https://img.shields.io/badge/Landing_Page-live-blue" alt="Landing Page"></a>
12
+ </p>
13
+
14
+ <p align="center">
15
+ Product standards for MCP Tool Shop.<br>
16
+ Templates, contracts, and adoption guides that define what "done" means before anything ships.
17
+ </p>
18
+
19
+ ---
20
+
21
+ ## なぜ
22
+
23
+ 以前は、「完了」とはコードが動作することを意味していました。しかし、それだけでは不十分です。製品とは、コードに加えて、安全性、エラー処理、ドキュメント、アイデンティティ、そして適切なリリース体制を意味します。Shipcheckは、その基準を定義します。
24
+
25
+ ## 内容
26
+
27
+ | 標準 | 対象範囲 |
28
+ |----------|----------------|
29
+ | [Ship Gate](templates/SHIP_GATE.md) | 厳格なチェック項目27個 + 柔軟なチェック項目4個を含む、リリース前のチェックリスト |
30
+ | [Error Contract](contracts/error-contract.md) | コード登録機能付きの、2段階構造のエラー基準 |
31
+ | [Security Baseline](templates/SECURITY.md) | レポートメール、対応までの時間、リスク範囲 |
32
+ | [Handbook](templates/HANDBOOK.md) | 複雑なツール向けの運用マニュアル |
33
+ | [Scorecard](templates/SCORECARD.md) | 修正前後の評価 |
34
+ | [Adoption Guide](ADOPTION.md) | Shipcheckを、30分以内に任意のレポジトリに適用 |
35
+
36
+ ## クイックスタート
37
+
38
+ 1. [ADOPTION.md](ADOPTION.md) を読んでください。
39
+ 2. `templates/SHIP_GATE.md` をレポジトリのルートディレクトリにコピーします。
40
+ 3. 該当する項目にチェックを入れ、該当しない項目には `SKIP:` と記述します。
41
+ 4. すべての厳格なチェック項目が完了したら、リリースします。
42
+
43
+ ## 仕組み
44
+
45
+ **厳格なチェック項目** (A~D) は、リリースをブロックします。
46
+
47
+ - **A. セキュリティ基準** — SECURITY.md、脅威モデル、機密情報の非保持、テレメトリーの非使用、デフォルトの安全対策
48
+ - **B. エラー処理** — 構造化されたエラー形式 (コード/メッセージ/ヒント/再試行可能)、安全な出力、エラー発生時の適切な対応
49
+ - **C. 運用者向けドキュメント** — README、CHANGELOG、LICENSE、ツールのドキュメント
50
+ - **D. リリース体制** — スクリプトの検証、バージョンの一致、依存関係のスキャン、ロックファイルの確認
51
+
52
+ **柔軟なチェック項目** (E) は、リリースをブロックしませんが、「全体像」を定義します。
53
+
54
+ - **E. アイデンティティ** — ロゴ、翻訳、ランディングページ、レポジトリのメタデータ
55
+
56
+ チェック項目は、**何を**満たすべきかを定義するものであり、**どのように**実装するかを定義するものではありません。適用範囲を示すタグ (`[all]`, `[npm]`, `[mcp]`, `[cli]`, `[desktop]`, `[vsix]`, `[container]`) は、該当する項目がないレポジトリでの不必要なチェックを避けるために使用されます。
57
+
58
+ ## エラー基準の概要
59
+
60
+ **Tier 1 — 形状 (必須):**
61
+
62
+ ```json
63
+ {
64
+ "code": "INPUT_TEXT_EMPTY",
65
+ "message": "Text must not be empty",
66
+ "hint": "Provide at least one character of text",
67
+ "retryable": false
68
+ }
69
+ ```
70
+
71
+ **Tier 2 — 基本タイプ + エラーコード (CLI/MCP/デスクトップ):**
72
+
73
+ | エラーコード | 意味 |
74
+ |-----------|---------|
75
+ | 0 | OK |
76
+ | 1 | ユーザーエラー (不正な入力、設定の欠如) |
77
+ | 2 | 実行時エラー (クラッシュ、バックエンドの障害) |
78
+ | 3 | 部分的な成功 (一部の項目が成功) |
79
+
80
+ エラーコードは、名前空間付きのプレフィックスを使用します: `IO_`, `CONFIG_`, `PERM_`, `DEP_`, `RUNTIME_`, `PARTIAL_`, `INPUT_`, `STATE_`. コードは、リリース後に安定します。
81
+
82
+ ## 参考実装
83
+
84
+ [mcp-voice-soundboard](https://github.com/mcp-tool-shop-org/mcp-voice-soundboard) は、Ship Gateを最初に通過したレポジトリであり、修正後に **46/50** のスコアを獲得しました。
85
+
86
+ ## 評価項目
87
+
88
+ | カテゴリ | スコア | 備考 |
89
+ |----------|-------|-------|
90
+ | A. セキュリティ | 10/10 | SECURITY.md、実行可能なコードなし、データ収集なし |
91
+ | B. エラー処理 | 該当なし | 標準レポジトリ — エラーに関するコードなし |
92
+ | C. 運用者向けドキュメント | 10/10 | README、CHANGELOG、ADOPTION、すべてのテンプレートがドキュメント化されています |
93
+ | D. リリース体制 | 8/10 | 検証/テストするコードなし、すべての標準がバージョン管理されています |
94
+ | E. アイデンティティ | 10/10 | ロゴ、翻訳、ランディングページ、メタデータ |
95
+ | **Total** | **38/40** | B は除外 (該当なし) |
96
+
97
+ ## ライセンス
98
+
99
+ [MIT](LICENSE)
100
+
101
+ ---
102
+
103
+ <p align="center">
104
+ Built by <a href="https://mcp-tool-shop.github.io/">MCP Tool Shop</a>
105
+ </p>
package/README.md ADDED
@@ -0,0 +1,105 @@
1
+ <p align="center">
2
+ <a href="README.ja.md">日本語</a> | <a href="README.zh.md">中文</a> | <a href="README.es.md">Español</a> | <a href="README.fr.md">Français</a> | <a href="README.hi.md">हिन्दी</a> | <a href="README.it.md">Italiano</a> | <a href="README.pt-BR.md">Português (BR)</a>
3
+ </p>
4
+
5
+ <p align="center">
6
+ <img src="https://raw.githubusercontent.com/mcp-tool-shop-org/brand/main/logos/shipcheck/readme.jpg" alt="Shipcheck" width="400">
7
+ </p>
8
+
9
+ <p align="center">
10
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT License"></a>
11
+ <a href="https://mcp-tool-shop-org.github.io/shipcheck/"><img src="https://img.shields.io/badge/Landing_Page-live-blue" alt="Landing Page"></a>
12
+ </p>
13
+
14
+ <p align="center">
15
+ Product standards for MCP Tool Shop.<br>
16
+ Templates, contracts, and adoption guides that define what "done" means before anything ships.
17
+ </p>
18
+
19
+ ---
20
+
21
+ ## Why
22
+
23
+ "Done" used to mean the code works. That's not enough. A product is code + safety + error handling + docs + identity + shipping hygiene. Shipcheck defines the bar.
24
+
25
+ ## What's in here
26
+
27
+ | Standard | What it covers |
28
+ |----------|----------------|
29
+ | [Ship Gate](templates/SHIP_GATE.md) | 27 hard-gate + 4 soft-gate pre-release checklist |
30
+ | [Error Contract](contracts/error-contract.md) | 2-tier structured error standard with code registry |
31
+ | [Security Baseline](templates/SECURITY.md) | Report email, response timeline, threat scope |
32
+ | [Handbook](templates/HANDBOOK.md) | Operational field manual for complex tools |
33
+ | [Scorecard](templates/SCORECARD.md) | Pre/post remediation scoring |
34
+ | [Adoption Guide](ADOPTION.md) | Apply shipcheck to any repo in <30 minutes |
35
+
36
+ ## Quick start
37
+
38
+ 1. Read [ADOPTION.md](ADOPTION.md)
39
+ 2. Copy `templates/SHIP_GATE.md` into your repo root
40
+ 3. Check off applicable items, mark non-applicable with `SKIP:`
41
+ 4. Ship when all hard gates pass
42
+
43
+ ## How it works
44
+
45
+ **Hard gates** (A-D) block release:
46
+
47
+ - **A. Security Baseline** — SECURITY.md, threat model, no secrets, no telemetry, default safety posture
48
+ - **B. Error Handling** — structured error shape (code/message/hint/retryable), safe output, graceful degradation
49
+ - **C. Operator Docs** — README, CHANGELOG, LICENSE, tool documentation
50
+ - **D. Shipping Hygiene** — verify script, version alignment, dependency scanning, lockfile
51
+
52
+ **Soft gate** (E) doesn't block but defines "whole":
53
+
54
+ - **E. Identity** — logo, translations, landing page, repo metadata
55
+
56
+ The gate says **what** must be true, not **how** to implement it. Applicability tags (`[all]`, `[npm]`, `[mcp]`, `[cli]`, `[desktop]`, `[vsix]`, `[container]`) prevent checkbox shame on repos where items don't apply.
57
+
58
+ ## Error contract at a glance
59
+
60
+ **Tier 1 — Shape (mandatory everywhere):**
61
+
62
+ ```json
63
+ {
64
+ "code": "INPUT_TEXT_EMPTY",
65
+ "message": "Text must not be empty",
66
+ "hint": "Provide at least one character of text",
67
+ "retryable": false
68
+ }
69
+ ```
70
+
71
+ **Tier 2 — Base type + exit codes (CLI/MCP/desktop):**
72
+
73
+ | Exit code | Meaning |
74
+ |-----------|---------|
75
+ | 0 | OK |
76
+ | 1 | User error (bad input, missing config) |
77
+ | 2 | Runtime error (crash, backend failure) |
78
+ | 3 | Partial success (some items succeeded) |
79
+
80
+ Error codes use namespaced prefixes: `IO_`, `CONFIG_`, `PERM_`, `DEP_`, `RUNTIME_`, `PARTIAL_`, `INPUT_`, `STATE_`. Codes are stable once released.
81
+
82
+ ## Reference implementation
83
+
84
+ [mcp-voice-soundboard](https://github.com/mcp-tool-shop-org/mcp-voice-soundboard) was the first repo to pass Ship Gate — scoring **46/50** after remediation.
85
+
86
+ ## Scorecard
87
+
88
+ | Category | Score | Notes |
89
+ |----------|-------|-------|
90
+ | A. Security | 10/10 | SECURITY.md, no executable code, no data collection |
91
+ | B. Error Handling | N/A | Standards repo — no code to error |
92
+ | C. Operator Docs | 10/10 | README, CHANGELOG, ADOPTION, all templates documented |
93
+ | D. Shipping Hygiene | 8/10 | No code to verify/test, all standards versioned |
94
+ | E. Identity | 10/10 | Logo, translations, landing page, metadata |
95
+ | **Total** | **38/40** | B excluded (not applicable) |
96
+
97
+ ## License
98
+
99
+ [MIT](LICENSE)
100
+
101
+ ---
102
+
103
+ <p align="center">
104
+ Built by <a href="https://mcp-tool-shop.github.io/">MCP Tool Shop</a>
105
+ </p>
@@ -0,0 +1,105 @@
1
+ <p align="center">
2
+ <a href="README.ja.md">日本語</a> | <a href="README.zh.md">中文</a> | <a href="README.es.md">Español</a> | <a href="README.fr.md">Français</a> | <a href="README.hi.md">हिन्दी</a> | <a href="README.it.md">Italiano</a> | <a href="README.md">English</a>
3
+ </p>
4
+
5
+ <p align="center">
6
+ <img src="https://raw.githubusercontent.com/mcp-tool-shop-org/brand/main/logos/shipcheck/readme.jpg" alt="Shipcheck" width="400">
7
+ </p>
8
+
9
+ <p align="center">
10
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT License"></a>
11
+ <a href="https://mcp-tool-shop-org.github.io/shipcheck/"><img src="https://img.shields.io/badge/Landing_Page-live-blue" alt="Landing Page"></a>
12
+ </p>
13
+
14
+ <p align="center">
15
+ Product standards for MCP Tool Shop.<br>
16
+ Templates, contracts, and adoption guides that define what "done" means before anything ships.
17
+ </p>
18
+
19
+ ---
20
+
21
+ ## Por que
22
+
23
+ "Concluído" costumava significar que o código funcionava. Isso não é suficiente. Um produto é código + segurança + tratamento de erros + documentação + identidade + higiene no processo de lançamento. O Shipcheck define o padrão.
24
+
25
+ ## O que está incluído aqui
26
+
27
+ | Padrão | O que isso cobre |
28
+ |----------|----------------|
29
+ | [Ship Gate](templates/SHIP_GATE.md) | Lista de verificação de pré-lançamento com 27 itens obrigatórios + 4 itens opcionais. |
30
+ | [Error Contract](contracts/error-contract.md) | Padrão estruturado de tratamento de erros com registro de código. |
31
+ | [Security Baseline](templates/SECURITY.md) | E-mail de relatório, tempo de resposta, escopo das ameaças. |
32
+ | [Handbook](templates/HANDBOOK.md) | Manual operacional para ferramentas complexas. |
33
+ | [Scorecard](templates/SCORECARD.md) | Pontuação antes e depois da correção. |
34
+ | [Adoption Guide](ADOPTION.md) | Aplique o Shipcheck a qualquer repositório em menos de 30 minutos. |
35
+
36
+ ## Como começar
37
+
38
+ 1. Leia [ADOPTION.md](ADOPTION.md)
39
+ 2. Copie `templates/SHIP_GATE.md` para a raiz do seu repositório.
40
+ 3. Marque os itens aplicáveis, e marque os itens não aplicáveis com `SKIP:`.
41
+ 4. Lance quando todos os itens obrigatórios forem aprovados.
42
+
43
+ ## Como funciona
44
+
45
+ **Itens obrigatórios** (A-D) bloqueiam o lançamento:
46
+
47
+ - **A. Segurança básica** — SECURITY.md, modelo de ameaças, sem segredos, sem telemetria, postura de segurança padrão.
48
+ - **B. Tratamento de erros** — estrutura de erro padronizada (código/mensagem/dica/tentável), saída segura, degradação graciosa.
49
+ - **C. Documentação para o usuário** — README, CHANGELOG, LICENÇA, documentação da ferramenta.
50
+ - **D. Higiene no processo de lançamento** — verificação de script, alinhamento de versão, análise de dependências, arquivo de bloqueio.
51
+
52
+ **Item opcional** (E) não bloqueia, mas define o "todo":
53
+
54
+ - **E. Identidade** — logotipo, traduções, página de destino, metadados do repositório.
55
+
56
+ O item indica **o que** deve ser verdadeiro, não **como** implementá-lo. As tags de aplicabilidade (`[all]`, `[npm]`, `[mcp]`, `[cli]`, `[desktop]`, `[vsix]`, `[container]`) evitam constrangimentos em repositórios onde os itens não se aplicam.
57
+
58
+ ## Contrato de erro em resumo
59
+
60
+ **Nível 1 — Estrutura (obrigatório em todos os lugares):**
61
+
62
+ ```json
63
+ {
64
+ "code": "INPUT_TEXT_EMPTY",
65
+ "message": "Text must not be empty",
66
+ "hint": "Provide at least one character of text",
67
+ "retryable": false
68
+ }
69
+ ```
70
+
71
+ **Nível 2 — Tipo base + códigos de saída (CLI/MCP/desktop):**
72
+
73
+ | Código de saída | Significado |
74
+ |-----------|---------|
75
+ | 0 | OK |
76
+ | 1 | Erro do usuário (entrada inválida, configuração ausente) |
77
+ | 2 | Erro em tempo de execução (falha, falha no backend) |
78
+ | 3 | Sucesso parcial (alguns itens foram bem-sucedidos) |
79
+
80
+ Os códigos de erro usam prefixos com namespace: `IO_`, `CONFIG_`, `PERM_`, `DEP_`, `RUNTIME_`, `PARTIAL_`, `INPUT_`, `STATE_`. Os códigos são estáveis após o lançamento.
81
+
82
+ ## Implementação de referência
83
+
84
+ [mcp-voice-soundboard](https://github.com/mcp-tool-shop-org/mcp-voice-soundboard) foi o primeiro repositório a passar no Ship Gate — obtendo uma pontuação de **46/50** após a correção.
85
+
86
+ ## Tabela de pontuação
87
+
88
+ | Categoria | Pontuação | Observações |
89
+ |----------|-------|-------|
90
+ | A. Segurança | 10/10 | SECURITY.md, sem código executável, sem coleta de dados. |
91
+ | B. Tratamento de erros | N/A | Repositório de padrões — sem código para tratamento de erros. |
92
+ | C. Documentação para o usuário | 10/10 | README, CHANGELOG, ADOPTION, todos os modelos documentados. |
93
+ | D. Higiene no processo de lançamento | 8/10 | Sem código para verificar/testar, todas as versões dos padrões versionadas. |
94
+ | E. Identidade | 10/10 | Logotipo, traduções, página de destino, metadados. |
95
+ | **Total** | **38/40** | B excluído (não aplicável) |
96
+
97
+ ## Licença
98
+
99
+ [MIT](LICENSE)
100
+
101
+ ---
102
+
103
+ <p align="center">
104
+ Built by <a href="https://mcp-tool-shop.github.io/">MCP Tool Shop</a>
105
+ </p>
package/README.zh.md ADDED
@@ -0,0 +1,105 @@
1
+ <p align="center">
2
+ <a href="README.ja.md">日本語</a> | <a href="README.md">English</a> | <a href="README.es.md">Español</a> | <a href="README.fr.md">Français</a> | <a href="README.hi.md">हिन्दी</a> | <a href="README.it.md">Italiano</a> | <a href="README.pt-BR.md">Português (BR)</a>
3
+ </p>
4
+
5
+ <p align="center">
6
+ <img src="https://raw.githubusercontent.com/mcp-tool-shop-org/brand/main/logos/shipcheck/readme.png" alt="Shipcheck" width="400">
7
+ </p>
8
+
9
+ <p align="center">
10
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT License"></a>
11
+ <a href="https://mcp-tool-shop-org.github.io/shipcheck/"><img src="https://img.shields.io/badge/Landing_Page-live-blue" alt="Landing Page"></a>
12
+ </p>
13
+
14
+ <p align="center">
15
+ Product standards for MCP Tool Shop.<br>
16
+ Templates, contracts, and adoption guides that define what "done" means before anything ships.
17
+ </p>
18
+
19
+ ---
20
+
21
+ ## 为什么
22
+
23
+ “完成”过去意味着代码可以正常运行。但这还不够。一个产品包括代码、安全性、错误处理、文档、身份标识以及发布流程。Shipcheck 定义了标准。
24
+
25
+ ## 内容
26
+
27
+ | 标准 | 涵盖内容 |
28
+ |----------|----------------|
29
+ | [Ship Gate](templates/SHIP_GATE.md) | 27 个硬性检查项 + 4 个软性检查项的预发布清单 |
30
+ | [Error Contract](contracts/error-contract.md) | 具有代码注册表的两级结构化错误标准 |
31
+ | [Security Baseline](templates/SECURITY.md) | 报告邮件、响应时间、风险范围 |
32
+ | [Handbook](templates/HANDBOOK.md) | 复杂工具的操作手册 |
33
+ | [Scorecard](templates/SCORECARD.md) | 修复前/后的评分 |
34
+ | [Adoption Guide](ADOPTION.md) | 将 Shipcheck 应用于任何仓库,只需 30 分钟 |
35
+
36
+ ## 快速开始
37
+
38
+ 1. 阅读 [ADOPTION.md](ADOPTION.md)
39
+ 2. 将 `templates/SHIP_GATE.md` 复制到您的仓库根目录
40
+ 3. 检查适用项,对于不适用项,使用 `SKIP:` 标记
41
+ 4. 在所有硬性检查项通过后发布
42
+
43
+ ## 工作原理
44
+
45
+ **硬性检查项 (A-D)** 会阻止发布:
46
+
47
+ - **A. 安全基线** — SECURITY.md,威胁模型,无敏感信息,无遥测,默认安全姿态
48
+ - **B. 错误处理** — 结构化的错误格式(代码/消息/提示/可重试),安全输出,优雅降级
49
+ - **C. 操作文档** — README,CHANGELOG,LICENSE,工具文档
50
+ - **D. 发布流程** — 验证脚本,版本对齐,依赖项扫描,锁定文件
51
+
52
+ **软性检查项 (E)** 不会阻止发布,但定义了“完整性”:
53
+
54
+ - **E. 身份标识** — logo,翻译,着陆页,仓库元数据
55
+
56
+ 检查项说明的是**必须**满足什么,而不是**如何**实现。适用性标签 (`[all]`, `[npm]`, `[mcp]`, `[cli]`, `[desktop]`, `[vsix]`, `[container]`) 避免在不适用的仓库中出现“未完成”的检查框。
57
+
58
+ ## 错误合约一览
59
+
60
+ **第一层 — 结构 (所有地方都必须满足):**
61
+
62
+ ```json
63
+ {
64
+ "code": "INPUT_TEXT_EMPTY",
65
+ "message": "Text must not be empty",
66
+ "hint": "Provide at least one character of text",
67
+ "retryable": false
68
+ }
69
+ ```
70
+
71
+ **第二层 — 基本类型 + 退出码 (CLI/MCP/桌面):**
72
+
73
+ | 退出码 | 含义 |
74
+ |-----------|---------|
75
+ | 0 | OK |
76
+ | 1 | 用户错误(无效输入,缺少配置) |
77
+ | 2 | 运行时错误(崩溃,后端故障) |
78
+ | 3 | 部分成功(某些项已成功) |
79
+
80
+ 错误代码使用命名空间前缀:`IO_`, `CONFIG_`, `PERM_`, `DEP_`, `RUNTIME_`, `PARTIAL_`, `INPUT_`, `STATE_`。代码在发布后会保持稳定。
81
+
82
+ ## 参考实现
83
+
84
+ [mcp-voice-soundboard](https://github.com/mcp-tool-shop-org/mcp-voice-soundboard) 是第一个通过 Ship Gate 的仓库,在修复后获得了 **46/50** 的评分。
85
+
86
+ ## 评分卡
87
+
88
+ | 类别 | 评分 | 备注 |
89
+ |----------|-------|-------|
90
+ | A. 安全性 | 10/10 | SECURITY.md,无可执行代码,无数据收集 |
91
+ | B. 错误处理 | N/A | 标准仓库 — 没有代码产生错误 |
92
+ | C. 操作文档 | 10/10 | README,CHANGELOG,ADOPTION,所有模板均已记录 |
93
+ | D. 发布流程 | 8/10 | 无代码可验证/测试,所有标准均已版本控制 |
94
+ | E. 身份标识 | 10/10 | Logo,翻译,着陆页,元数据 |
95
+ | **Total** | **38/40** | B 排除(不适用) |
96
+
97
+ ## 许可证
98
+
99
+ [MIT](LICENSE)
100
+
101
+ ---
102
+
103
+ <p align="center">
104
+ Built by <a href="https://mcp-tool-shop.github.io/">MCP Tool Shop</a>
105
+ </p>
@@ -0,0 +1,245 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync, readdirSync, writeFileSync, existsSync, copyFileSync } from "node:fs";
4
+ import { join, resolve, dirname } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const PKG_ROOT = resolve(__dirname, "..");
9
+ const CWD = process.cwd();
10
+
11
+ const BOLD = "\x1b[1m";
12
+ const GREEN = "\x1b[32m";
13
+ const YELLOW = "\x1b[33m";
14
+ const CYAN = "\x1b[36m";
15
+ const DIM = "\x1b[2m";
16
+ const RESET = "\x1b[0m";
17
+
18
+ function log(msg) { console.log(msg); }
19
+ function ok(msg) { log(`${GREEN}✓${RESET} ${msg}`); }
20
+ function skip(msg) { log(`${DIM} skip${RESET} ${msg}`); }
21
+ function warn(msg) { log(`${YELLOW}!${RESET} ${msg}`); }
22
+
23
+ // --- Detect repo type ---
24
+
25
+ function detectTypes() {
26
+ const tags = new Set(["all"]);
27
+
28
+ if (existsSync(join(CWD, "package.json"))) {
29
+ const pkg = JSON.parse(readFileSync(join(CWD, "package.json"), "utf8"));
30
+ tags.add("npm");
31
+ // Check if it's an MCP server
32
+ const desc = (pkg.description || "").toLowerCase();
33
+ const keywords = (pkg.keywords || []).map(k => k.toLowerCase());
34
+ if (desc.includes("mcp") || keywords.includes("mcp") || keywords.includes("model-context-protocol")) {
35
+ tags.add("mcp");
36
+ }
37
+ // Check for CLI bin
38
+ if (pkg.bin) {
39
+ tags.add("cli");
40
+ }
41
+ }
42
+
43
+ if (existsSync(join(CWD, "pyproject.toml")) || existsSync(join(CWD, "setup.py"))) {
44
+ tags.add("pypi");
45
+ }
46
+
47
+ if (existsSync(join(CWD, "Dockerfile")) || existsSync(join(CWD, "docker-compose.yml"))) {
48
+ tags.add("container");
49
+ }
50
+
51
+ // VS Code extension
52
+ const vsceFiles = [".vscodeignore", "vsc-extension-quickstart.md"];
53
+ if (vsceFiles.some(f => existsSync(join(CWD, f)))) {
54
+ tags.add("vsix");
55
+ }
56
+ if (existsSync(join(CWD, "package.json"))) {
57
+ try {
58
+ const pkg = JSON.parse(readFileSync(join(CWD, "package.json"), "utf8"));
59
+ if (pkg.engines?.vscode) tags.add("vsix");
60
+ } catch {}
61
+ }
62
+
63
+ // Desktop app signals
64
+ const desktopSignals = ["tauri.conf.json", "electron-builder.yml", "forge.config.js"];
65
+ if (desktopSignals.some(f => existsSync(join(CWD, f)))) {
66
+ tags.add("desktop");
67
+ }
68
+ // .NET desktop (MAUI, WinUI)
69
+ try {
70
+ for (const f of readdirSync(CWD).filter(f => f.endsWith(".csproj"))) {
71
+ const content = readFileSync(join(CWD, f), "utf8");
72
+ if (content.includes("Maui") || content.includes("WinUI")) {
73
+ tags.add("desktop");
74
+ }
75
+ }
76
+ } catch {}
77
+
78
+ return [...tags];
79
+ }
80
+
81
+ // --- Commands ---
82
+
83
+ function initCommand() {
84
+ log(`\n${BOLD}shipcheck init${RESET}\n`);
85
+
86
+ const types = detectTypes();
87
+ log(`${CYAN}Detected tags:${RESET} ${types.map(t => `[${t}]`).join(" ")}\n`);
88
+
89
+ const files = [
90
+ { src: "templates/SHIP_GATE.md", dest: "SHIP_GATE.md" },
91
+ { src: "templates/SECURITY.md", dest: "SECURITY.md", skipIf: "SECURITY.md" },
92
+ { src: "templates/CHANGELOG.md", dest: "CHANGELOG.md", skipIf: "CHANGELOG.md" },
93
+ { src: "templates/SCORECARD.md", dest: "SCORECARD.md" },
94
+ ];
95
+
96
+ for (const { src, dest, skipIf } of files) {
97
+ const destPath = join(CWD, dest);
98
+ if (skipIf && existsSync(destPath)) {
99
+ skip(`${dest} already exists`);
100
+ continue;
101
+ }
102
+ const srcPath = join(PKG_ROOT, src);
103
+ if (!existsSync(srcPath)) {
104
+ warn(`Template not found: ${src}`);
105
+ continue;
106
+ }
107
+
108
+ let content = readFileSync(srcPath, "utf8");
109
+
110
+ // Inject detected tags into SHIP_GATE header
111
+ if (dest === "SHIP_GATE.md") {
112
+ content = content.replace(
113
+ /<!-- repo type tags -->/,
114
+ types.map(t => `\`[${t}]\``).join(" ")
115
+ );
116
+ }
117
+
118
+ // Fill SECURITY.md placeholders
119
+ if (dest === "SECURITY.md") {
120
+ // Try to read author email from package.json
121
+ try {
122
+ const pkg = JSON.parse(readFileSync(join(CWD, "package.json"), "utf8"));
123
+ if (pkg.bugs?.url) {
124
+ content = content.replace(
125
+ /<!-- report-email -->/g,
126
+ pkg.bugs.url
127
+ );
128
+ }
129
+ } catch {}
130
+ }
131
+
132
+ writeFileSync(destPath, content, "utf8");
133
+ ok(dest);
134
+ }
135
+
136
+ log(`\n${BOLD}Next steps:${RESET}`);
137
+ log(` 1. Open ${CYAN}SHIP_GATE.md${RESET} and check off applicable items`);
138
+ log(` 2. Mark non-applicable items with ${DIM}SKIP: reason${RESET}`);
139
+ log(` 3. Ship when all hard gates (A-D) pass`);
140
+ log(`\n Read ${CYAN}ADOPTION.md${RESET} for the full walkthrough:`);
141
+ log(` ${DIM}https://github.com/mcp-tool-shop-org/shipcheck/blob/main/ADOPTION.md${RESET}\n`);
142
+ }
143
+
144
+ function auditCommand() {
145
+ log(`\n${BOLD}shipcheck audit${RESET}\n`);
146
+
147
+ if (!existsSync(join(CWD, "SHIP_GATE.md"))) {
148
+ warn("No SHIP_GATE.md found. Run 'shipcheck init' first.\n");
149
+ process.exit(1);
150
+ }
151
+
152
+ const content = readFileSync(join(CWD, "SHIP_GATE.md"), "utf8");
153
+ const lines = content.split("\n");
154
+
155
+ let checked = 0;
156
+ let unchecked = 0;
157
+ let skipped = 0;
158
+ const gaps = [];
159
+
160
+ for (const line of lines) {
161
+ const trimmed = line.trim();
162
+ if (trimmed.startsWith("- [x]") || trimmed.startsWith("- [X]")) {
163
+ checked++;
164
+ } else if (trimmed.startsWith("- [ ]")) {
165
+ if (trimmed.includes("SKIP:")) {
166
+ skipped++;
167
+ } else {
168
+ unchecked++;
169
+ // Extract the item text
170
+ const text = trimmed.replace(/^- \[ \] /, "").substring(0, 80);
171
+ gaps.push(text);
172
+ }
173
+ }
174
+ }
175
+
176
+ const total = checked + unchecked + skipped;
177
+ const passRate = total > 0 ? Math.round((checked / (checked + unchecked)) * 100) : 0;
178
+
179
+ log(`${GREEN}Checked:${RESET} ${checked}`);
180
+ log(`${YELLOW}Unchecked:${RESET} ${unchecked}`);
181
+ log(`${DIM}Skipped:${RESET} ${skipped}`);
182
+ log(`${BOLD}Pass rate:${RESET} ${passRate}%\n`);
183
+
184
+ if (gaps.length > 0) {
185
+ log(`${YELLOW}${BOLD}Remaining gaps:${RESET}`);
186
+ for (const gap of gaps.slice(0, 10)) {
187
+ log(` ${YELLOW}○${RESET} ${gap}`);
188
+ }
189
+ if (gaps.length > 10) {
190
+ log(` ${DIM}...and ${gaps.length - 10} more${RESET}`);
191
+ }
192
+ log("");
193
+ }
194
+
195
+ if (unchecked === 0) {
196
+ log(`${GREEN}${BOLD}All hard gates pass. Ship it.${RESET}\n`);
197
+ } else {
198
+ log(`${YELLOW}${unchecked} item(s) still need attention.${RESET}\n`);
199
+ process.exit(1);
200
+ }
201
+ }
202
+
203
+ function helpCommand() {
204
+ log(`
205
+ ${BOLD}shipcheck${RESET} — product standards for MCP Tool Shop
206
+
207
+ ${BOLD}Usage:${RESET}
208
+ npx @mcptoolshop/shipcheck init Copy templates into current repo
209
+ npx @mcptoolshop/shipcheck audit Check SHIP_GATE.md progress
210
+ npx @mcptoolshop/shipcheck help Show this message
211
+
212
+ ${BOLD}What it does:${RESET}
213
+ init Detects repo type (npm, pypi, mcp, cli, etc.)
214
+ Copies SHIP_GATE.md, SECURITY.md, CHANGELOG.md, SCORECARD.md
215
+ Skips files that already exist (except SHIP_GATE + SCORECARD)
216
+
217
+ audit Counts checked/unchecked/skipped items in SHIP_GATE.md
218
+ Reports pass rate and lists remaining gaps
219
+ Exits 0 if all gates pass, 1 if gaps remain
220
+
221
+ ${DIM}https://github.com/mcp-tool-shop-org/shipcheck${RESET}
222
+ `);
223
+ }
224
+
225
+ // --- Main ---
226
+
227
+ const command = process.argv[2] || "help";
228
+
229
+ switch (command) {
230
+ case "init":
231
+ initCommand();
232
+ break;
233
+ case "audit":
234
+ auditCommand();
235
+ break;
236
+ case "help":
237
+ case "--help":
238
+ case "-h":
239
+ helpCommand();
240
+ break;
241
+ default:
242
+ warn(`Unknown command: ${command}`);
243
+ helpCommand();
244
+ process.exit(1);
245
+ }